home *** CD-ROM | disk | FTP | other *** search
/ Aminet 45 / Aminet 45 (2001)(GTI - Schatztruhe)[!][Oct 2001].iso / Aminet / dev / gui / FoxGuiSource.lha / FoxLibSource / ListBox.c < prev    next >
C/C++ Source or Header  |  2001-07-07  |  65KB  |  2,385 lines

  1. /* FoxGUI - The fast, flexible, free Amiga GUI system
  2.     Copyright (C) 2001 Simon Fox (Foxysoft)
  3.  
  4. This library is free software; you can redistribute it and/ormodify it under the terms of the GNU Lesser General PublicLicense as published by the Free Software Foundation; eitherversion 2.1 of the License, or (at your option) any later version.This library is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without even the implied warranty ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNULesser General Public License for more details.You should have received a copy of the GNU Lesser General PublicLicense along with this library; if not, write to the Free SoftwareFoundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  5. Foxysoft: www.foxysoft.co.uk      Email:simon@foxysoft.co.uk                */
  6.  
  7. /******************************************************************************
  8.  * Shared library code.  Cannot call functions which use exit() such as:
  9.  * printf(), fprintf()
  10.  *
  11.  * Otherwise:
  12.  * The linker returns "__XCEXIT undefined" and the program will fail.
  13.  * This is because you must not exit() a library!
  14.  *
  15.  * Also:
  16.  * proto/exec.h must be included instead of clib/exec_protos.h and
  17.  * __USE_SYSBASE must be defined.
  18.  *
  19.  * Otherwise:
  20.  * The linker returns "Absolute reference to symbol _SysBase" and the
  21.  * library crashes.  Presumably the same is true for the other protos.
  22.  ******************************************************************************/
  23.  
  24. #define __USE_SYSBASE
  25.  
  26. #include <proto/mathieeedoubbas.h>
  27. #include <stdarg.h>
  28. #include <string.h>
  29. #include <math.h>
  30.  
  31. #include <proto/intuition.h>
  32. #include <proto/graphics.h>
  33. #include "/FoxInclude/foxgui.h"
  34. #include "FoxGuiTools.h"
  35.  
  36. void FOXLIB SetListBoxTopNum(REGA0 ListBox *lb, REGD0 int num, REGD1 BOOL refresh)
  37.     {
  38.     if (lb && num)
  39.         {
  40.         lb->TopShown = num;
  41.         if (refresh)
  42.             ListBoxRefresh(lb);
  43.         else
  44.             lb->modified = TRUE;
  45.         }
  46.     }
  47.  
  48. ListBoxItem* FOXLIB ItemElem(REGA0 ListBox *lb, REGD0 int target)
  49.     {
  50.     int n = 1;
  51.     ListBoxItem *TargElem = lb->FirstItem;
  52.     while (TargElem && n < target)
  53.         {
  54.         if (TargElem->NextText)
  55.             {
  56.             if (TargElem->TopEdge < TargElem->NextText->TopEdge)
  57.                 n++;
  58.             }
  59.         else
  60.             n++;
  61.         TargElem = TargElem->NextText;
  62.         }
  63.     if (n != target)
  64.         return NULL;  // We failed to find the item number specified.
  65.     else
  66.         return TargElem;
  67.     }
  68.  
  69. int ItemNum(ListBox *lb, ListBoxItem *target)
  70.     {
  71.     ListBoxItem *it = lb->FirstItem;
  72.     int TargNum = 1;
  73.  
  74.     while (it && it != target)
  75.         {
  76.         if (it->NextText)
  77.             {
  78.             if (it->TopEdge < it->NextText->TopEdge)
  79.                 TargNum++;
  80.             }
  81.         else
  82.             TargNum++;
  83.         it = it->NextText;
  84.         }
  85.     if (it != target)
  86.         return 0;  // We failed to find the text specified.
  87.     else
  88.         return TargNum;
  89.     }
  90.  
  91. static __inline __regargs void ListBoxClipOn(ListBox *lb, int tabnum)
  92.     {
  93.     if (lb && !(lb->WidgetData->flags & LB_CLIPPED))
  94.         {
  95.         struct Region *rg;
  96.         int llborder = lb->WidgetData->left + lb->LBorder + 2;
  97.         int left, right;
  98.  
  99.         if (tabnum > 0)
  100.         {
  101.             left = lb->WidgetData->left + lb->TabStop[tabnum - 1] + lb->xOffset;
  102.             if (left < llborder)
  103.                 left = llborder;
  104.         }
  105.         else
  106.             left = llborder;
  107.         if (tabnum != -1 && lb->TabStop[tabnum] != 0)
  108.             right = lb->WidgetData->left + lb->TabStop[tabnum] - 2 + lb->xOffset;
  109.         else
  110.             right = lb->WidgetData->left + lb->points[0] - lb->LBorder - 2;
  111.  
  112.         rg = ClipGuiWindow(lb->Win, left, lb->WidgetData->top + lb->TBorder + 1,
  113.                 right, lb->WidgetData->top + lb->WidgetData->height - (lb->LR ? SCROLL_BUTTON_HEIGHT : 0) - lb->TBorder);
  114.         if (rg)
  115.             DisposeRegion(rg);
  116.         lb->WidgetData->flags |= LB_CLIPPED;
  117.         }
  118.     }
  119.  
  120. static __inline __regargs void ListBoxClipOff(ListBox *lb)
  121.     {
  122.     if (lb && lb->WidgetData->flags & LB_CLIPPED)
  123.         {
  124.         UnclipGuiWindow(lb->Win);
  125.         lb->WidgetData->flags &= ~LB_CLIPPED;
  126.         }
  127.     }
  128.  
  129. __regargs ListBoxItem *PrintTabClippedText(ListBox *lb, ListBoxItem *i, int top)
  130. {
  131.     ListBoxItem *nexttoprint = NULL;
  132.  
  133.     if (lb && i)
  134.     {
  135.         register int topedge = i->TopEdge;
  136.         register int lxoffset = lb->WidgetData->left + lb->xOffset;
  137.  
  138.         if (lb->TabStop)
  139.         {
  140.             register int tabnum = 0;
  141.             register ListBoxItem *n;
  142.  
  143.             while ((tabnum == 0 || (tabnum > 0 && lb->TabStop[tabnum - 1])) && i && i->TopEdge == topedge)
  144.             {
  145.                 n = i->NextText;
  146.                 ListBoxClipOn(lb, tabnum);
  147.                 i->NextText = NULL;
  148.                 PrintIText(lb->Win->Win->RPort, i, lxoffset, top);
  149.                 i->NextText = n;
  150.                 ListBoxClipOff(lb);
  151.                 i = n;
  152.                 tabnum++;
  153.             }
  154.             nexttoprint = i;
  155.         }
  156.         else
  157.         {
  158.             register ListBoxItem *p = i, *first = i;
  159.  
  160.             ListBoxClipOn(lb, -1);
  161.  
  162.             while (i && i->TopEdge == topedge)
  163.             {
  164.                 p = i;
  165.                 i = i->NextText;
  166.             }
  167.  
  168.             p->NextText = NULL;
  169.             PrintIText(lb->Win->Win->RPort, first, lxoffset, top);
  170.             p->NextText = i;
  171.             nexttoprint = i;
  172.             ListBoxClipOff(lb);
  173.         }
  174.     }
  175.     return nexttoprint;
  176. }
  177.  
  178. void ListBoxRehilight(ListBox *lb, int HiNum, ListBoxItem *HiElem, BOOL unhilight,
  179.         BOOL hilight)
  180.     {
  181. //    BOOL unclip = FALSE;
  182. //    ListBoxItem *store;
  183.     ListBoxItem *it; //, *prit;
  184.     int numlines = NumLines(lb), top;
  185.  
  186.     // If neither the number or the element has been specified then unhilight only.
  187.  
  188.     if (HiNum && !HiElem)
  189.         /*    The user has specified which item to hilight by number only.  We need to
  190.             know both the number and the element so let's find the element. */
  191.         if (!(HiElem = ItemElem(lb, HiNum)))
  192.             return;  // We failed to find the item number specified.
  193.  
  194.     if (HiElem && !HiNum)
  195.         /*    The user has specified which item to hilight by element only.  We need
  196.             to know both the number and the element so let's find the number. */
  197.         if (!(HiNum = ItemNum(lb, HiElem)))
  198.             return;  // We failed to find the text specified.
  199.  
  200. /*    if (!(lb->WidgetData->flags & LB_CLIPPED))
  201.         {
  202.         ListBoxClipOn(lb, -1);
  203.         unclip = TRUE;
  204.         } */
  205.  
  206.     if (lb->NoTitles)
  207.         top = lb->WidgetData->top + ((lb->NoTitles + 1 - lb->TopShown) * lb->Font->ta_YSize) + (3 * lb->TBorder) + 4;
  208.     else
  209.         top = lb->WidgetData->top + ((1 - lb->TopShown) * lb->Font->ta_YSize) + lb->TBorder + 1;
  210.  
  211.     // Unhilight previous selection
  212.     if (lb->HiItem)
  213.         {
  214.         it = lb->HiItem;
  215. //        prit = NULL;
  216.         while (it && it->TopEdge == lb->HiItem->TopEdge)
  217.             {
  218.             it->DrawMode = JAM2;
  219. //            prit = it;
  220.             it = it->NextText;
  221.             }
  222.         if (unhilight && lb->HiNum >= lb->TopShown && lb->HiNum <= numlines + lb->TopShown - 1 && lb->hidden == 0)
  223.             {
  224. //            store = prit->NextText;
  225. //            prit->NextText = NULL;
  226.             AreaColFill(lb->Win->Win->RPort, lb->WidgetData->left + lb->HiItem->LeftEdge, top + lb->HiItem->TopEdge, lb->MaxIntuiLen, lb->Font->ta_YSize, GetBackCol(lb->WidgetData->Parent));
  227.             PrintTabClippedText(lb, lb->HiItem, top);
  228. //            PrintIText(lb->Win->Win->RPort, lb->HiItem, lb->WidgetData->left + lb->xOffset, top);
  229. //            prit->NextText = store;
  230.             }
  231.         }
  232.  
  233.     // Now hilight the new item...
  234.     lb->HiItem = HiElem;
  235.     lb->HiNum = HiNum;
  236.  
  237.     if (lb->HiItem)
  238.         {
  239.         it = lb->HiItem;
  240. //        prit = NULL;
  241.         while (it && it->TopEdge == lb->HiItem->TopEdge)
  242.             {
  243.             it->DrawMode = JAM2 | INVERSVID;
  244. //            prit = it;
  245.             it = it->NextText;
  246.             }
  247.         if (hilight && HiNum >= lb->TopShown && HiNum <= numlines + lb->TopShown - 1 && lb->hidden == 0)
  248.             {
  249. //            store = prit->NextText;
  250. //            prit->NextText = NULL;
  251.             AreaColFill(lb->Win->Win->RPort, lb->WidgetData->left + HiElem->LeftEdge, top + HiElem->TopEdge, lb->MaxIntuiLen, lb->Font->ta_YSize, lb->FrontPen);
  252.             PrintTabClippedText(lb, HiElem, top);
  253. //            PrintIText(lb->Win->Win->RPort, HiElem, lb->WidgetData->left + lb->xOffset, top);
  254. //            prit->NextText = store;
  255.             }
  256.         }
  257. /*    if (unclip)
  258.         ListBoxClipOff(lb); */
  259.     }
  260.  
  261. void FOXLIB SetListBoxHiNum(REGA0 ListBox *lb, REGD0 int num, REGD1 BOOL refresh)
  262.     {
  263.     if (lb && num >= 0)
  264.         {
  265.         ListBoxRehilight(lb, num, NULL, refresh && !lb->modified, refresh && !lb->modified);
  266.         if (refresh && lb->modified)
  267.             ListBoxRefresh(lb);
  268.         if (!refresh)
  269.             lb->modified = TRUE;
  270.         }
  271.     }
  272.  
  273. // This function is called by FoxGui to unhilight an item that the pointer was held over
  274. // when the user was dragging something into this list box, without hilighting another item.
  275. void ClearListBoxDropNum(ListBox *lb, ListBoxItem *OldHiItem)
  276.     {
  277.     ListBoxItem *it;
  278.     int numlines = NumLines(lb), top, itemnum = ItemNum(lb, OldHiItem);
  279.  
  280.     // Unhilight previous selection
  281.     if (OldHiItem && OldHiItem != lb->HiItem)
  282.         {
  283.         if (lb->NoTitles)
  284.             top = lb->WidgetData->top + ((lb->NoTitles + 1 - lb->TopShown) * lb->Font->ta_YSize) + (3 * lb->TBorder) + 4;
  285.         else
  286.             top = lb->WidgetData->top + ((1 - lb->TopShown) * lb->Font->ta_YSize) + lb->TBorder + 1;
  287.  
  288.         it = OldHiItem;
  289.         while (it && it->TopEdge == OldHiItem->TopEdge)
  290.             {
  291.             it->DrawMode = JAM2;
  292.             it = it->NextText;
  293.             }
  294.         if (itemnum >= lb->TopShown && itemnum <= numlines + lb->TopShown - 1 && lb->hidden == 0)
  295.             {
  296.             AreaColFill(lb->Win->Win->RPort, lb->WidgetData->left + OldHiItem->LeftEdge, top + OldHiItem->TopEdge, lb->MaxIntuiLen, lb->Font->ta_YSize, GetBackCol(lb->WidgetData->Parent));
  297.             PrintTabClippedText(lb, OldHiItem, top);
  298.             }
  299.         }
  300.     }
  301.  
  302. // This function is called by FoxGui to hilight the item that the pointer is held over
  303. // when the user is dragging something into this list box.
  304. ListBoxItem *SetListBoxDropNum(ListBox *lb, int HiNum, ListBoxItem *OldHiItem)
  305.     {
  306.     ListBoxItem *it, *HiElem = ItemElem(lb, HiNum);
  307.     int numlines = NumLines(lb), top;
  308.  
  309.     if (OldHiItem == HiElem)
  310.         return HiElem; // Nothing to do.
  311.  
  312.     if (lb->NoTitles)
  313.         top = lb->WidgetData->top + ((lb->NoTitles + 1 - lb->TopShown) * lb->Font->ta_YSize) + (3 * lb->TBorder) + 4;
  314.     else
  315.         top = lb->WidgetData->top + ((1 - lb->TopShown) * lb->Font->ta_YSize) + lb->TBorder + 1;
  316.  
  317.     // Unhilight previous selection
  318.     if (OldHiItem && OldHiItem != lb->HiItem)
  319.         {
  320.         int itemnum = ItemNum(lb, OldHiItem);
  321.  
  322.         it = OldHiItem;
  323.         while (it && it->TopEdge == OldHiItem->TopEdge)
  324.             {
  325.             it->DrawMode = JAM2;
  326.             it = it->NextText;
  327.             }
  328.         if (itemnum >= lb->TopShown && itemnum <= numlines + lb->TopShown - 1 && lb->hidden == 0)
  329.             {
  330.             AreaColFill(lb->Win->Win->RPort, lb->WidgetData->left + OldHiItem->LeftEdge, top + OldHiItem->TopEdge, lb->MaxIntuiLen, lb->Font->ta_YSize, GetBackCol(lb->WidgetData->Parent));
  331.             PrintTabClippedText(lb, OldHiItem, top);
  332.             }
  333.         }
  334.  
  335.     // Now hilight the new item...
  336.     // If HiElem == lb->HiItem then the item will already be hilighted - no point in doing it again!
  337.     if (HiElem && HiElem != lb->HiItem)
  338.         {
  339.         it = HiElem;
  340.         while (it && it->TopEdge == HiElem->TopEdge)
  341.             {
  342.             it->DrawMode = JAM2 | INVERSVID;
  343.             it = it->NextText;
  344.             }
  345.         if (HiNum >= lb->TopShown && HiNum <= numlines + lb->TopShown - 1 && lb->hidden == 0)
  346.             {
  347.             AreaColFill(lb->Win->Win->RPort, lb->WidgetData->left + HiElem->LeftEdge, top + HiElem->TopEdge, lb->MaxIntuiLen, lb->Font->ta_YSize, lb->FrontPen);
  348.             PrintTabClippedText(lb, HiElem, top);
  349.             }
  350.         }
  351.     return HiElem;
  352.     }
  353.  
  354. void FOXLIB SetListBoxHiElem(REGA0 ListBox *lb, REGA1 ListBoxItem *item, REGD0 BOOL refresh)
  355.     {
  356.     if (lb && item)
  357.         {
  358.         ListBoxRehilight(lb, 0, item, refresh && !lb->modified, refresh && !lb->modified);
  359.         if (refresh && lb->modified)
  360.             ListBoxRefresh(lb);
  361.         if (!refresh)
  362.             lb->modified = TRUE;
  363.         }
  364.     }
  365.  
  366. ListBoxItem *GetTopElem(ListBox *lb, int *topnum)
  367.     {
  368.     ListBoxItem *start = lb->FirstItem;
  369.     int num = 1;
  370.     while (start && num < lb->TopShown)
  371.         {
  372.         if (start->NextText)
  373.             {
  374.             if (start->TopEdge < start->NextText->TopEdge)
  375.                 num++;
  376.             }
  377.         else
  378.             num++;
  379.         start = start->NextText;
  380.         }
  381.     if (topnum)
  382.         *topnum = num;
  383.     return start;
  384.     }
  385.  
  386. int ListBoxItemFromXY(ListBox *lb, long x, long y, ListBoxItem **Item, int *ItemNum)
  387.     {
  388.     int ItemLine = 0;
  389.     if (Item)
  390.         *Item = NULL;
  391.     if (ItemNum)
  392.         *ItemNum = 0;
  393.  
  394.     if (lb)
  395.         {
  396.         int titleheight = lb->NoTitles ? (lb->NoTitles * lb->Font->ta_YSize) + (2 * lb->TBorder) + 3 : 0;
  397.  
  398.         // Convert the coordinates into offsets from the corner of the list box
  399.         x -= lb->WidgetData->left;
  400.         y -= (lb->WidgetData->top + titleheight);
  401.         if (x >= 0 && x < lb->points[12] && y >= 0 && y <= lb->WidgetData->height - 1 - (lb->LR ? SCROLL_BUTTON_HEIGHT : 0))
  402.             {
  403.             // The user clicked an item not a title
  404.             int line = ((y - lb->TBorder) / lb->Font->ta_YSize) + 1;
  405.             int n, ItemClicked;
  406.             ListBoxItem *SelectedElem = GetTopElem(lb, &n);
  407.  
  408.             /* If the user clicked in the top border, pretend he clicked on the first
  409.                 line */
  410.             line = max(line, 1);
  411.             ItemClicked = line + lb->TopShown - 1;
  412.  
  413.             while (n < ItemClicked && SelectedElem)
  414.                 {
  415.                 if (SelectedElem->NextText)
  416.                     {
  417.                     if (SelectedElem->TopEdge < SelectedElem->NextText->TopEdge)
  418.                         n++;
  419.                     }
  420.                 else
  421.                     n++;
  422.                 SelectedElem = SelectedElem->NextText;
  423.                 }
  424.             if (n <= lb->NoItems) // User did not click in the blank space below the last item
  425.                 *ItemNum = n;
  426.             if (Item)
  427.                 *Item = SelectedElem;
  428.             ItemLine = line;
  429.             }
  430.         }
  431.     return ItemLine;
  432.     }
  433.  
  434. int Select(ListBox *lb, long x, long y, unsigned long seconds, unsigned long micros, Frame **FrameDownPtr)
  435.     {
  436.     static unsigned long last_seconds = 0;
  437.     static unsigned long last_micros = 0;
  438.     static int last_selected = -1;
  439.  
  440.     if (lb)
  441.         {
  442.         ListBoxItem *SelectedElem;
  443.         int line, n;
  444.  
  445.         line = ListBoxItemFromXY(lb, x, y, &SelectedElem, &n);
  446.  
  447.         if (SelectedElem)
  448.             {
  449.             ListBoxRehilight(lb, n, SelectedElem, TRUE, TRUE);
  450.  
  451.             /*    Is this the second click of a double-click?  (If it is but the list-box has no
  452.                 double-click function then treat this as a second single-click). */
  453.             if ((lb->WidgetData->flags & LB_DBLCLICK) && lb->Eventfn &&
  454.                         DoubleClick(last_seconds, last_micros, seconds, micros) &&
  455.                         line == last_selected)
  456.                 {
  457.                 // This is the second click of a double click.
  458.                 int Stop;
  459.                 last_selected = -1;
  460.                 *FrameDownPtr = NULL;
  461.                 Stop = (*(lb->Eventfn))(lb, LB_DBLCLICK, lb->HiNum, NULL);
  462.                 return Stop;
  463.                 }
  464.             else // This is a single click.
  465.                 {
  466.                 last_seconds = seconds;
  467.                 last_micros = micros;
  468.                 last_selected = line;
  469.                 if ((lb->WidgetData->flags & LB_SELECT) && lb->Eventfn)
  470.                     {
  471.                     int Stop;
  472. // Taken out the line below so that a list box can have a select and a drag event.  Not sure whether
  473. // there will be any side effects of removing it.
  474.                     // *FrameDownPtr = NULL;
  475.                     Stop = (*(lb->Eventfn))(lb, LB_SELECT, lb->HiNum, NULL);
  476.                     return Stop;
  477.                     }
  478.                 }
  479.             }
  480.         }
  481.     return GUI_CONTINUE;
  482.     }
  483.  
  484. static void UpdateHorizScroller(ListBox *nlb)
  485.     {
  486.     unsigned short body, pot;
  487.  
  488.     FindScrollerValues(nlb->LongestIntuiLen, nlb->MaxIntuiLen, 0 - nlb->xOffset, nlb->Font->ta_YSize, &body, &pot);
  489.     NewModifyProp(&nlb->LR->ScrollGad, nlb->Win->Win, NULL, AUTOKNOB | FREEHORIZ | PROPNEWLOOK, pot, 0, body, 0, 1);
  490.     }
  491.  
  492. static void RefreshVertScroller(ListBox *lb)
  493.     {
  494.     if (lb->UD)
  495.         {
  496.         RefreshGList(&lb->UD->ScrollGad, lb->Win->Win, NULL, 1);
  497.         if (lb->UD->ScrollUp)
  498.             RefreshGList(&lb->UD->ScrollUp->button, lb->Win->Win, NULL, 1);
  499.         if (lb->UD->ScrollDown)
  500.             RefreshGList(&lb->UD->ScrollDown->button, lb->Win->Win, NULL, 1);
  501.         }
  502.     }
  503.  
  504. static void RefreshHorizScroller(ListBox *lb)
  505.     {
  506.     if (lb->LR)
  507.         {
  508.         RefreshGList(&lb->LR->ScrollGad, lb->Win->Win, NULL, 1);
  509.         if (lb->LR->ScrollUp)
  510.             RefreshGList(&lb->LR->ScrollUp->button, lb->Win->Win, NULL, 1);
  511.         if (lb->LR->ScrollDown)
  512.             RefreshGList(&lb->LR->ScrollDown->button, lb->Win->Win, NULL, 1);
  513.         }
  514.     }
  515.  
  516. void FOXLIB ListBoxRefresh(REGA0 ListBox *lb)
  517.     {
  518.     if (lb && lb->hidden == 0)
  519.         {
  520. //        BOOL unclip = FALSE;
  521.         unsigned short body, pot;
  522.         ListBoxItem *text, *store, *firstitem, *i;
  523.         int n, numlines = NumLines(lb), top;
  524.  
  525.         if (lb->NoTitles)
  526.         {
  527.             MakeBevel(&lb->LightBorder, &lb->DarkBorder, lb->points, lb->WidgetData->left, lb->WidgetData->top +
  528.                     (lb->NoTitles * lb->Font->ta_YSize) + (2 * lb->TBorder) + 3, lb->WidgetData->width - (lb->UD ?
  529.                     SCROLL_BUTTON_WIDTH : 0), lb->WidgetData->height - (lb->LR ? SCROLL_BUTTON_HEIGHT + 1 : 0) - (3 + (2 *
  530.                     lb->TBorder) + (lb->NoTitles * lb->Font->ta_YSize)), TRUE);
  531.             MakeBevel(&lb->TitleLightBorder, &lb->TitleDarkBorder, lb->titlebevelpoints, lb->WidgetData->left, lb->WidgetData->top,
  532.                     lb->WidgetData->width - (lb->UD ? SCROLL_BUTTON_WIDTH : 0), 2 + (2 * lb->TBorder) + (lb->NoTitles *
  533.                     lb->Font->ta_YSize), TRUE);
  534.             lb->DarkBorder.NextBorder = &lb->TitleLightBorder;
  535.             if (lb->UD)
  536.                 lb->TitleDarkBorder.NextBorder = &lb->UD->LightBorder;
  537.             else if (lb->LR)
  538.                 lb->TitleDarkBorder.NextBorder = &lb->LR->LightBorder;
  539.             else
  540.                 lb->TitleDarkBorder.NextBorder = NULL;
  541.         }
  542.         else
  543.         {
  544.             MakeBevel(&lb->LightBorder, &lb->DarkBorder, lb->points, lb->WidgetData->left, lb->WidgetData->top, lb->WidgetData->width -
  545.                     (lb->UD ? SCROLL_BUTTON_WIDTH : 0), lb->WidgetData->height - (lb->LR ? SCROLL_BUTTON_HEIGHT + 1 : 0),
  546.                     TRUE);
  547.             if (lb->UD)
  548.                 lb->DarkBorder.NextBorder = &lb->UD->LightBorder;
  549.             else if (lb->LR)
  550.                 lb->DarkBorder.NextBorder = &lb->LR->LightBorder;
  551.             else
  552.                 lb->DarkBorder.NextBorder = NULL;
  553.         }
  554.  
  555.         AreaColFill(lb->Win->Win->RPort, lb->WidgetData->left + 2, lb->WidgetData->top + 1,
  556.                 lb->WidgetData->width - (lb->UD ? SCROLL_BUTTON_WIDTH : 0) - 4, lb->WidgetData->height - (lb->LR ? SCROLL_BUTTON_HEIGHT : 0) - 2, GetBackCol(lb->WidgetData->Parent));
  557.         DrawBorder(lb->Win->Win->RPort, &lb->LightBorder, 0, 0);
  558.  
  559. /*        if (!(lb->WidgetData->flags & LB_CLIPPED))
  560.             {
  561.             ListBoxClipOn(lb, -1);
  562.             unclip = TRUE;
  563.             } */
  564.  
  565.         // Print the titles
  566.         if (lb->FirstTitle)
  567.             {
  568.             ListBoxItem *i = lb->FirstTitle;
  569.             while (i)
  570.                 i = PrintTabClippedText(lb, i, lb->WidgetData->top + 1 + lb->TBorder);
  571. //            PrintIText(lb->Win->Win->RPort, lb->FirstTitle, lb->WidgetData->left + lb->xOffset, lb->WidgetData->top + 1 + lb->TBorder);
  572.             }
  573.  
  574.         // Now print as many items as possible in the remaining space
  575.         if (lb->NoItems <= numlines)
  576.             {
  577.             firstitem = lb->FirstItem;
  578.             lb->TopShown = 1;
  579.             }
  580.         else
  581.             {
  582.             if (!lb->TopShown)
  583.                 {
  584.                 firstitem = lb->FirstItem;
  585.                 lb->TopShown = 1;
  586.                 }
  587.             else
  588.                 {
  589.                 ListBoxItem *fi;
  590.                 int top = lb->TopShown;
  591.                 while (lb->NoItems - top + 1 < numlines)
  592.                     top--;
  593.                 lb->TopShown = max(top, 1);
  594.                 fi = ItemElem(lb, lb->TopShown);
  595.                 if (fi)
  596.                     firstitem = fi;
  597.                 else
  598.                     firstitem = NULL;
  599.                 }
  600.             }
  601.  
  602.         text = firstitem;
  603.         n = 1;
  604.         while (n < numlines && text)
  605.             {
  606.             if (text->NextText)
  607.                 {
  608.                 if (text->TopEdge < text->NextText->TopEdge)
  609.                     n++;
  610.                 }
  611.             else
  612.                 n++;
  613.             text = text->NextText;
  614.             }
  615.         while (text && text->NextText)
  616.             if (text->NextText->TopEdge == text->TopEdge)
  617.                 text = text->NextText;
  618.             else
  619.                 break;
  620.         if (text)
  621.             {
  622.             store = text->NextText;
  623.             text->NextText = NULL;
  624.             }
  625.  
  626.         if (lb->NoTitles)
  627.             top = lb->WidgetData->top + ((lb->NoTitles + 1 - lb->TopShown) * lb->Font->ta_YSize) + (3 * lb->TBorder) + 4;
  628.         else
  629.             top = lb->WidgetData->top + ((1 - lb->TopShown) * lb->Font->ta_YSize) + lb->TBorder + 1;
  630.         if (lb->HiNum >= lb->TopShown && lb->HiNum <= lb->TopShown + numlines - 1)
  631.             AreaColFill(lb->Win->Win->RPort, lb->WidgetData->left + lb->HiItem->LeftEdge, top + lb->HiItem->TopEdge, lb->MaxIntuiLen, lb->Font->ta_YSize, lb->FrontPen);
  632.         i = firstitem;
  633.         while (i)
  634.             i = PrintTabClippedText(lb, i, top);
  635. //        PrintIText(lb->Win->Win->RPort, firstitem, lb->WidgetData->left + lb->xOffset, top);
  636.         if (text)
  637.             text->NextText = store;
  638.  
  639. /*        if (unclip)
  640.             ListBoxClipOff(lb); */
  641.  
  642.         if (lb->UD)
  643.             {
  644.             if (lb->itemlist)
  645.             {
  646.                 int top = 0, maxlen = 0, maxtop = 0;
  647.  
  648.                 FindMaxSizes(lb->itemlist, &maxlen, &maxtop, &top);
  649.                 FindScrollerValues(maxtop + lb->Font->ta_YSize, lb->WidgetData->height - 4 - (2 * lb->TBorder), CalcItemTop(lb->topshown), lb->Font->ta_YSize, &body, &pot);
  650.             }
  651.             else
  652.                 FindScrollerValues(lb->NoItems, numlines, lb->TopShown - 1, 1, &body, &pot);
  653.             NewModifyProp(&lb->UD->ScrollGad, lb->Win->Win, NULL, AUTOKNOB | FREEVERT | PROPNEWLOOK, 0, pot, 0, body, 1);
  654.             }
  655.         if (lb->LR)
  656.             {
  657.             UpdateHorizScroller(lb);
  658.             RefreshHorizScroller(lb);
  659.             }
  660.         if (lb->UD)
  661.             RefreshVertScroller(lb);
  662.  
  663.         lb->modified = FALSE;
  664.         }
  665.     }
  666.  
  667. static void RedisplayList(ListBox *lb, ListBoxItem *OldTop, int NewTopNum,
  668.         ListBoxItem *NewTop, int NumLines, int NewHiNum, ListBoxItem *NewHiElem, BOOL refreshscroller)
  669.     {
  670.     if (lb && OldTop && NewTop)
  671.         {
  672.         unsigned short body, pot;
  673.         register ListBoxItem *o = OldTop, *n = NewTop;
  674.         register ListBoxItem *onext, *nnext;
  675.         register int num = 1, FrontPenStore;
  676.         int oldmult, newmult;
  677.         BYTE BackPenCol = GetBackCol(lb->WidgetData->Parent);
  678.  
  679.         if (lb->NoTitles)
  680.         {
  681.             oldmult = lb->WidgetData->top + ((lb->NoTitles + 1 - lb->TopShown) * lb->Font->ta_YSize) + (3 * lb->TBorder) + 4;
  682.             newmult = lb->WidgetData->top + ((lb->NoTitles + 1 - NewTopNum) * lb->Font->ta_YSize) + (3 * lb->TBorder) + 4;
  683.         }
  684.         else
  685.         {
  686.             oldmult = lb->WidgetData->top + ((1 - lb->TopShown) * lb->Font->ta_YSize) + lb->TBorder + 1;
  687.             newmult = lb->WidgetData->top + ((1 - NewTopNum) * lb->Font->ta_YSize) + lb->TBorder + 1;
  688.         }
  689.  
  690.         if (NewHiNum || NewHiElem)
  691.             {
  692.             /*    We're going to rehilight at the same time.  We can do it here (for
  693.                 speed) rather than in a seperate call to ListBoxRehilight().  This means
  694.                 using as few calls to PrintIText() as possible. */
  695.             if (!NewHiNum)
  696.                 NewHiNum = ItemNum(lb, NewHiElem);
  697.             else if (!NewHiElem)
  698.                 NewHiElem = ItemElem(lb, NewHiNum);
  699.             if (NewHiNum && NewHiElem)
  700.                 {
  701.                 register ListBoxItem *it;
  702.                 if (lb->HiItem)
  703.                     {
  704.                     it = lb->HiItem;
  705.                     while (it && it->TopEdge == lb->HiItem->TopEdge)
  706.                         {
  707.                         it->DrawMode = JAM2;
  708.                         it = it->NextText;
  709.                         }
  710.                     }
  711.                 it = NewHiElem;
  712.                 while (it && it->TopEdge == NewHiElem->TopEdge)
  713.                     {
  714.                     it->DrawMode = JAM2 | INVERSVID;
  715.                     it = it->NextText;
  716.                     }
  717.                 lb->HiItem = NewHiElem;
  718.                 lb->HiNum = NewHiNum;
  719.                 }
  720.             }
  721.  
  722.         /* Line by line we need to delete the line of text that was there previously
  723.             and print the new line.  Each iteration of this loop deals with one line.
  724.             It would be simpler to treat the existing list as one list of IntuiText,
  725.             delete the whole lot in one go and then print the new list in one go too
  726.             but that causes too much flicker. */
  727.         if (lb->hidden == 0)
  728.             while (num <= NumLines && o && n)
  729.                 {
  730.                 // Store details of the old line of text
  731.                 FrontPenStore = o->FrontPen;
  732.  
  733.                 /* Change the colour of the old line of text so that printing it again
  734.                     will delete it */
  735.                 o->FrontPen = o->BackPen;
  736.  
  737.                 onext = o->NextText;
  738.                 while (onext && onext->TopEdge == o->TopEdge)
  739.                     {
  740.                     onext->FrontPen = onext->BackPen;
  741.                     onext = onext->NextText;
  742.                     }
  743.                 nnext = n->NextText;
  744.                 while (nnext && nnext->TopEdge == n->TopEdge)
  745.                     nnext = nnext->NextText;
  746.  
  747.                 // Un-print the old text
  748.                 PrintTabClippedText(lb, o, oldmult);
  749.  
  750.                 // If we're hilighting or un-hilighting, paint the background.
  751.                 if (n == lb->HiItem)
  752.                     AreaColFill(lb->Win->Win->RPort, lb->WidgetData->left + n->LeftEdge, newmult + n->TopEdge, lb->MaxIntuiLen, lb->Font->ta_YSize, lb->FrontPen);
  753.                 else if (o == lb->HiItem)
  754.                     AreaColFill(lb->Win->Win->RPort, lb->WidgetData->left + o->LeftEdge, oldmult + o->TopEdge, lb->MaxIntuiLen, lb->Font->ta_YSize, BackPenCol);
  755.                 // Print the new text.
  756.                 PrintTabClippedText(lb, n, newmult);
  757.  
  758.                 // Restore the details of the old and new lines
  759.                 do {
  760.                     o->FrontPen = FrontPenStore;
  761.                     o = o->NextText;
  762.                     } while (o != onext);
  763.  
  764.                 // Now for the next line...
  765.                 num++;
  766.                 n = nnext;
  767.                 }
  768.         lb->TopShown = NewTopNum;
  769.  
  770.         if (lb->UD && lb->hidden == 0 && refreshscroller)
  771.             {
  772.             FindScrollerValues(lb->NoItems, NumLines, NewTopNum - 1, 1, &body, &pot);
  773.             NewModifyProp(&lb->UD->ScrollGad, lb->Win->Win, NULL, AUTOKNOB | FREEVERT | PROPNEWLOOK, 0, pot, 0, body, 1);
  774.             }
  775.         lb->modified = FALSE;
  776.         }
  777.     }
  778.  
  779. void ListBoxScrollUp(ListBox *nlb, BOOL refreshscroller)
  780.     {
  781.     int oldtopnum, numlines = NumLines(nlb);
  782.     ListBoxItem *OldTop = GetTopElem(nlb, &oldtopnum);
  783.     ListBoxItem *NewTop = nlb->FirstItem;
  784.  
  785.     while (NewTop)
  786.         if (NewTop->TopEdge + nlb->Font->ta_YSize == OldTop->TopEdge)
  787.             break;
  788.         else
  789.             NewTop = NewTop->NextText;
  790.  
  791.     if (NewTop && nlb->TopShown > 1)
  792.         {
  793.         int NewHiNum = 0;
  794.         if ((nlb->WidgetData->flags & LB_REHILIGHT_ON_SCROLL) && nlb->HiNum > nlb->TopShown + numlines - 2)
  795.             NewHiNum = oldtopnum + numlines - 2;
  796.         RedisplayList(nlb, OldTop, oldtopnum - 1, NewTop, numlines, NewHiNum, NULL, refreshscroller);
  797.         }
  798.     }
  799.  
  800. ListBoxItem *NextItem(ListBoxItem *Item)
  801.     {
  802.     if (Item)
  803.         {
  804.         ListBoxItem *ni = Item->NextText;
  805.  
  806.         while (ni && ni->TopEdge == Item->TopEdge)
  807.             ni = ni->NextText;
  808.         return ni;
  809.         }
  810.     return NULL;
  811.     }
  812.  
  813. void ListBoxScrollDown(ListBox *nlb, BOOL refreshscroller)
  814.     {
  815.     int oldtopnum, numlines = NumLines(nlb);
  816.     ListBoxItem *OldTop = GetTopElem(nlb, &oldtopnum);
  817.  
  818.     if (OldTop)
  819.         {
  820.         ListBoxItem *NewTop = NextItem(OldTop);
  821.         if (NewTop && numlines + nlb->TopShown - 1 < nlb->NoItems)
  822.             {
  823.             int NewHiNum = 0;
  824.             if ((nlb->WidgetData->flags & LB_REHILIGHT_ON_SCROLL) && nlb->HiNum && nlb->HiNum < nlb->TopShown + 1)
  825.                 NewHiNum = oldtopnum + 1;
  826.             RedisplayList(nlb, OldTop, oldtopnum + 1, NewTop, numlines, NewHiNum, NULL, refreshscroller);
  827.             }
  828.         }
  829.     }
  830.  
  831. void FOXLIB SortListBox(REGA0 ListBox *p, REGD0 int flags, REGD1 int startnum, REGD2 BOOL refresh)
  832.    {
  833.     ListBoxItem *StartItem, *Previous = NULL, *it;
  834.  
  835.    Diagnostic("SortListBox", ENTER, TRUE);
  836.    if (!p)
  837.       {
  838.       Diagnostic("SortListBox", EXIT, FALSE);
  839.       return;
  840.       }
  841.     if (p->NoItems < 2)
  842.         {
  843.       Diagnostic("SortListBox", EXIT, TRUE);
  844.         return;
  845.         }
  846.  
  847.     if (StartItem = ItemElem(p, startnum))
  848.         {
  849.         if (startnum > 1)
  850.             {
  851.             if (Previous = ItemElem(p, startnum - 1))
  852.                 Previous = SetLast(Previous);
  853.             if (!Previous)
  854.                 {
  855.                Diagnostic("SortListBox", EXIT, FALSE);
  856.                 return;
  857.                 }
  858.             }
  859.  
  860.         SortITextList(&StartItem, flags);
  861.         if (Previous)
  862.             Previous->NextText = StartItem;
  863.         else
  864.             p->FirstItem = StartItem;
  865.  
  866.         // Now reset the topedges of each intuitext item
  867.         if (it = p->FirstItem)
  868.             {
  869.             int top = it->TopEdge, t = 0;
  870.  
  871.             while (it)
  872.                 {
  873.                 if (it->TopEdge != top)
  874.                     {
  875.                     top = it->TopEdge;
  876.                     t++;
  877.                     }
  878.                 it->TopEdge = t * p->Font->ta_YSize;
  879.                 it = it->NextText;
  880.                 }
  881.             }
  882.         if (p->HiNum) // If an item was hilighted before sorting, reset to the first item.
  883.             SetListBoxHiNum(p, 1, FALSE);
  884.         SetListBoxTopNum(p, 1, refresh);
  885.         }
  886.     else
  887.        Diagnostic("SortListBox", EXIT, FALSE);
  888.    Diagnostic("SortListBox", EXIT, TRUE);
  889.    }
  890.  
  891. int FOXLIB NoTitles(REGA0 ListBox *lb)
  892.     {
  893.     if (lb)
  894.         return lb->NoTitles;
  895.     else
  896.         return 0;
  897.     }
  898.  
  899. int FOXLIB NoLines(REGA0 ListBox *lb)
  900.     {
  901.     if (lb)
  902.         return NumLines(lb);
  903.     else
  904.         return 0;
  905.     }
  906.  
  907. int FOXLIB TopNum(REGA0 ListBox *lb)
  908.     {
  909.     if (lb)
  910.         return lb->TopShown;
  911.     return 0;
  912.     }
  913.  
  914. int FOXLIB HiNum(REGA0 ListBox *lb)
  915.     {
  916.     if (lb)
  917.         return lb->HiNum;
  918.     return 0;
  919.     }
  920.  
  921. ListBoxItem* FOXLIB HiElem(REGA0 ListBox *lb)
  922.     {
  923.     if (lb)
  924.         if (lb->HiItem)
  925.             return lb->HiItem;
  926.     return NULL;
  927.     }
  928.  
  929. char* FOXLIB HiText(REGA0 ListBox *lb)
  930.     {
  931.     if (lb)
  932.         if (lb->HiItem)
  933.             return lb->HiItem->IText;
  934.     return NULL;
  935.     }
  936.  
  937. int FOXLIB FindListText(REGA0 ListBox *lb, REGA1 char *text, REGD0 int reqcolumn)
  938.     {
  939.     if (lb && text)
  940.         {
  941.         int line = 1, column = 1;
  942.         struct IntuiText *it = lb->FirstItem;
  943.         while (it)
  944.             {
  945.             if (strcmp(it->IText, text) == 0 && (column == reqcolumn || reqcolumn == 0))
  946.                 return line;
  947.             if (it->NextText)
  948.                 if (it->NextText->TopEdge > it->TopEdge)
  949.                 {
  950.                     line++;
  951.                     column = 0;
  952.                 }
  953.             column++;
  954.             it = it->NextText;
  955.             }
  956.         }
  957.     return 0;
  958.     }
  959.  
  960. char* FOXLIB ListColumnText(REGA0 ListBox *lb, REGD0 int col)
  961.     {
  962.     if (lb)
  963.         if (lb->HiItem)
  964.             {
  965.             if (col == 0)
  966.                 return lb->HiItem->IText;
  967.             else
  968.                 {
  969.                 struct IntuiText *it = lb->HiItem;
  970.                 int top = it->TopEdge, ncol = 0;
  971.                 while (ncol < col && it)
  972.                     {
  973.                     it = it->NextText;
  974.                     ncol++;
  975.                     }
  976.                 if (it)
  977.                     if (it->TopEdge == top)
  978.                         return it->IText;
  979.                 }
  980.             }
  981.     return NULL;
  982.     }
  983.  
  984. int ScrollUpButtFn(PushButton *pb)
  985.     {
  986.     ListBoxScrollUp((ListBox *) pb->WidgetData->ParentControl, TRUE);
  987.     return GUI_CONTINUE;
  988.     }
  989.  
  990. int ScrollDownButtFn(PushButton *pb)
  991.     {
  992.     ListBoxScrollDown((ListBox *) pb->WidgetData->ParentControl, TRUE);
  993.     return GUI_CONTINUE;
  994.     }
  995.  
  996. int ScrollLeftButtFn(PushButton *pb)
  997.     {
  998.     ListBox *lb = (ListBox*) pb->WidgetData->ParentControl;
  999.     if (lb->xOffset < 0)
  1000.         {
  1001.         lb->xOffset += lb->Font->ta_YSize;
  1002.         if (lb->xOffset > 0)
  1003.             lb->xOffset = 0;
  1004.         UpdateHorizScroller(lb);
  1005.         ListBoxRefresh(lb);
  1006.         }
  1007.     return GUI_CONTINUE;
  1008.     }
  1009.  
  1010. int ScrollRightButtFn(PushButton *pb)
  1011.     {
  1012.     ListBox *lb = (ListBox*) pb->WidgetData->ParentControl;
  1013.     if (lb->xOffset + lb->LongestIntuiLen > lb->MaxIntuiLen)
  1014.         {
  1015.         lb->xOffset -= lb->Font->ta_YSize;
  1016.         if (lb->xOffset + lb->LongestIntuiLen < lb->MaxIntuiLen)
  1017.             lb->xOffset = lb->MaxIntuiLen - lb->LongestIntuiLen;
  1018.         UpdateHorizScroller(lb);
  1019.         ListBoxRefresh(lb);
  1020.         }
  1021.     return GUI_CONTINUE;
  1022.     }
  1023.  
  1024. static ListBoxItem *MakeIntuiTextList(ListBox *nlb, char *title, int frontpen, int backpen,
  1025.         int topedge, int drawmode, ListBoxItem **last)
  1026.     {
  1027.     // Construct a list of IntuiText's suitable for storing a tabbed string.
  1028.     short numtabs = 0, tabstops = 0;
  1029.     int index = 0, len;
  1030.     ListBoxItem *LastTitle = NULL, *it, *FirstTitle = NULL;
  1031.     int *ts;
  1032.     char *thisstr = title;
  1033.  
  1034.     if (nlb && title)
  1035.         {
  1036.         if (nlb->TabStop)
  1037.             while (nlb->TabStop[tabstops] != 0)
  1038.                 tabstops++;
  1039.  
  1040.         // Count the usable tabs in the title string
  1041.         len = strlen(title);
  1042.         while (index < len)
  1043.             if (title[index++] == '\t' && numtabs < tabstops)
  1044.                     numtabs++;
  1045.  
  1046.         ts = NULL;
  1047.  
  1048.         // Create numtabs+1 IntuiText's
  1049.         for (index = 0; index <= numtabs; index++)
  1050.             {
  1051.             int numchars;
  1052.             char *nextstrstart = strchr(thisstr, '\t');
  1053.  
  1054.             if (index < numtabs && nextstrstart)
  1055.                 {
  1056.                 char *tmp = thisstr;
  1057.                 numchars = 0;
  1058.                 while (tmp < nextstrstart)
  1059.                     {
  1060.                     numchars++;
  1061.                     tmp = &(tmp[1]);
  1062.                     }
  1063.                 }
  1064.             else
  1065.                 numchars = strlen(thisstr);
  1066.  
  1067.             it = (ListBoxItem *) GuiMalloc(sizeof(ListBoxItem), 0);
  1068.             if (!it)
  1069.                 break; // Leave the loop but keep any we've allocated successfully
  1070.             if (last)
  1071.                 *last = it;
  1072.             if (!(it->IText = (char *) GuiMalloc((numchars + 1) * sizeof(char), 0)))
  1073.                 {
  1074.                 GuiFree(it);
  1075.                 break; // Leave the loop but keep any we've allocated successfully
  1076.                 }
  1077.  
  1078.             it->TopEdge = topedge;
  1079.             it->ITextFont = nlb->Font;
  1080.             it->FrontPen = frontpen;
  1081.             it->BackPen = backpen;
  1082.             it->DrawMode = drawmode;
  1083.             it->NextText = NULL;
  1084.             it->LeftEdge = ListBoxLeftEdge(nlb, (ts ? *ts : 0));
  1085.  
  1086.             strncpy(it->IText, thisstr, numchars);
  1087.             it->IText[numchars] = 0;
  1088.  
  1089.             // if it's the last one, get rid of any extra tabs by replacing with spaces.
  1090.             if (index == numtabs)
  1091.                 {
  1092.                 int loop;
  1093.                 for (loop = 0; loop < strlen(it->IText); loop++)
  1094.                     if (it->IText[loop] == '\t')
  1095.                         it->IText[loop] = ' ';
  1096.                 }
  1097.  
  1098.             if (LastTitle)
  1099.                 LastTitle->NextText = it;
  1100.             else
  1101.                 FirstTitle = it;
  1102.             LastTitle = it;
  1103.  
  1104.             thisstr = nextstrstart;
  1105.             if (thisstr)
  1106.                 thisstr = &(thisstr[1]); // jump over the tab.
  1107.             if (ts)
  1108.                 ts = (ts[1] ? &ts[1] : NULL);
  1109.             else
  1110.                 ts = nlb->TabStop;
  1111.             }
  1112.         }
  1113.     return FirstTitle;
  1114.     }
  1115.  
  1116. BOOL FOXLIB AddListBoxTitle(REGA0 ListBox *nlb, REGA1 char *title, REGD0 BOOL refresh)
  1117.     {
  1118.     unsigned short body, pot;
  1119.     int numlines, i;
  1120.     ListBoxItem *NewTitle, *last = NULL;
  1121.     Diagnostic("AddListBoxTitle", ENTER, TRUE);
  1122.  
  1123.     if (!(nlb && title))
  1124.         return Diagnostic("AddListBoxTitle", EXIT, FALSE);
  1125.  
  1126.     numlines = NumLines(nlb);
  1127.  
  1128.     // Check whether there's room for another title (must leave room for at least
  1129.     // one item and a horizontal scroll bar if there isn't one already)
  1130.     if (((nlb->NoTitles + 2) * nlb->Font->ta_YSize) + (4 * nlb->TBorder) + SCROLL_BUTTON_HEIGHT + 5 > nlb->WidgetData->height)
  1131.         return Diagnostic("AddListBoxTitle", EXIT, FALSE);
  1132.  
  1133.     if (!(NewTitle = MakeIntuiTextList(nlb, title, Gui.TextCol, 0, nlb->NoTitles * nlb->Font->ta_YSize, JAM1,
  1134.             &last)))
  1135.         return Diagnostic("AddListBoxTitle", EXIT, FALSE);
  1136.  
  1137.     if (nlb->FirstTitle == NULL)
  1138.         nlb->FirstTitle = NewTitle;
  1139.     else
  1140.         {
  1141.         ListBoxItem *next = nlb->FirstTitle;
  1142.         while (next->NextText)
  1143.             next = next->NextText;
  1144.         next->NextText = NewTitle;
  1145.         }
  1146.  
  1147.     (nlb->NoTitles)++;
  1148.     if (refresh && nlb->hidden == 0)
  1149.         {
  1150.         ListBoxRefresh(nlb);
  1151.  
  1152.         if (nlb->UD)
  1153.             {
  1154.             FindScrollerValues(nlb->NoItems, numlines, nlb->TopShown - 1, 1, &body, &pot);
  1155.             NewModifyProp(&nlb->UD->ScrollGad, nlb->Win->Win, NULL, AUTOKNOB | FREEVERT | PROPNEWLOOK, 0, pot, 0, body, 1);
  1156.             }
  1157.         }
  1158.     else
  1159.         nlb->modified = TRUE;
  1160.  
  1161.     if (last)
  1162.         {
  1163.         int Length = IntuiTextLength(last);
  1164.         int Tab = last->LeftEdge - nlb->LBorder - 2;
  1165.         if (Length + Tab > nlb->LongestIntuiLen)
  1166.             {
  1167.             nlb->LongestIntuiLen = Length + Tab;
  1168.             if (nlb->LR)
  1169.                 UpdateHorizScroller(nlb);
  1170.             }
  1171.         }
  1172.  
  1173.     /* We need a loop here because we may have to make a horizontal scroller but not a vertical scroller
  1174.         so we make the horizontal one but doing that might then make us need a vertical scroller so we
  1175.         need to come back around the loop to create it! */
  1176.     for (i = 0; i < 2; i++)
  1177.         {
  1178.         if (nlb->NoItems > NumLines(nlb) && !nlb->UD)
  1179.             {
  1180.             MakeVerticalScroller(nlb, ScrollUpButtFn, ScrollDownButtFn);
  1181.             if (nlb->UD)
  1182.                 {
  1183.                 nlb->WidgetData->flags |= SYS_LB_VSCROLL;
  1184.                 ResizeListBox(nlb, nlb->WidgetData->left, nlb->WidgetData->top, nlb->WidgetData->width, nlb->WidgetData->height, (double) 1.0, (double) 1.0, TRUE);
  1185.                 if (nlb->hidden == 0)
  1186.                     {
  1187.                     AddGadget(nlb->Win->Win, &nlb->UD->ScrollGad, ~0);
  1188.                     RefreshGList(&nlb->UD->ScrollGad, nlb->Win->Win, NULL, 1);
  1189.                     }
  1190.                 if (!nlb->Enabled)
  1191.                     DisableScroller(nlb->UD);
  1192.                 if (refresh)
  1193.                     ListBoxRefresh(nlb);
  1194.                 }
  1195.             }
  1196.  
  1197.         if (nlb->LongestIntuiLen > nlb->MaxIntuiLen && !nlb->LR)
  1198.             {
  1199.             nlb->WidgetData->flags |= SYS_LB_HSCROLL;
  1200.             ResizeListBox(nlb, nlb->WidgetData->left, nlb->WidgetData->top, nlb->WidgetData->width, nlb->WidgetData->height, (double) 1.0, (double) 1.0, TRUE);
  1201.             MakeHorizontalScroller(nlb, ScrollLeftButtFn, ScrollRightButtFn);
  1202.             if (refresh)
  1203.                 ListBoxRefresh(nlb);
  1204.             }
  1205.         }
  1206.     return Diagnostic("AddListBoxTitle", EXIT, TRUE);
  1207.     }
  1208.  
  1209. static void FreeITextList(ListBoxItem *it)
  1210.     {
  1211.     ListBoxItem *next;
  1212.     while (it)
  1213.         {
  1214.         next = it->NextText;
  1215.         if (it->IText)
  1216.             GuiFree(it->IText);
  1217.         GuiFree(it);
  1218.         it = next;
  1219.         }
  1220.     }
  1221.  
  1222. static void CheckDestroyScrollers(ListBox *lb, BOOL refresh)
  1223.     {
  1224.     int i;
  1225.  
  1226.     // Check both twice because destroying the second could remove the need for the first.
  1227.     for (i = 0; i < 2; i++)
  1228.         {
  1229.         if (lb->LR)
  1230.             {
  1231.             int MaxAvailableLen = lb->MaxIntuiLen + SCROLL_BUTTON_WIDTH;
  1232.  
  1233.             if (lb->LongestIntuiLen <= MaxAvailableLen)
  1234.                 DestroyHorizontalScroller(lb, refresh);
  1235.             }
  1236.         if (lb->UD)
  1237.             {
  1238.             // Recalc NumLines each time because destroying the LR scroller will change it.
  1239.             if (lb->NoItems <= NumLines(lb))
  1240.                 DestroyVerticalScroller(lb, refresh);
  1241.             }
  1242.         }
  1243.     }
  1244.  
  1245. static int ItemLength(ListBox *lb, ListBoxItem *last)
  1246.     {
  1247.     // last is the last item in the IntuiTextList being added.
  1248.     if (last && lb)
  1249.         {
  1250.         int Tab = last->LeftEdge - lb->LBorder - 2;
  1251.         return Tab + IntuiTextLength(last);
  1252.         }
  1253.     return 0;
  1254.     }
  1255.  
  1256. static void SetLongestIntuiLen(ListBox *lb, int flags, BOOL refresh)
  1257.     {
  1258.     // flags: 1 = titles, 2 = items, 3 = both
  1259.     ListBoxItem *lbi = (flags == 2 ? lb->FirstItem : lb->FirstTitle);
  1260.     int il;
  1261.  
  1262.     lb->LongestIntuiLen = 0;
  1263.     while (flags > 0)
  1264.         {
  1265.         while (lbi)
  1266.             {
  1267.             if (lbi->NextText == NULL || lbi->NextText->TopEdge > lbi->TopEdge)
  1268.                 if ((il = ItemLength(lb, lbi)) > lb->LongestIntuiLen)
  1269.                     lb->LongestIntuiLen = il;
  1270.             lbi = lbi->NextText;
  1271.             }
  1272.         flags -= 2;
  1273.         lbi = lb->FirstItem;
  1274.         }
  1275.     CheckDestroyScrollers(lb, refresh);
  1276.     if (lb->LR && refresh)
  1277.         UpdateHorizScroller(lb);
  1278.     }
  1279.  
  1280. static void CheckMakeScrollers(ListBox *lb, BOOL refresh)
  1281.     {
  1282.     int i;
  1283.  
  1284.     /* We need a loop here because we may have to make a horizontal scroller but not a vertical scroller
  1285.         so we make the horizontal one but doing that might then make us need a vertical scroller so we
  1286.         need to come back around the loop to create it! */
  1287.     for (i = 0; i < 2; i++)
  1288.         {
  1289.         if (lb->NoItems > NumLines(lb) && !lb->UD)
  1290.             {
  1291.             MakeVerticalScroller(lb, ScrollUpButtFn, ScrollDownButtFn);
  1292.             if (lb->UD)
  1293.                 {
  1294.                 lb->WidgetData->flags |= SYS_LB_VSCROLL;
  1295.                 ResizeListBox(lb, lb->WidgetData->left, lb->WidgetData->top, lb->WidgetData->width, lb->WidgetData->height, (double) 1.0, (double) 1.0, TRUE);
  1296.                 if (lb->hidden == 0)
  1297.                     {
  1298.                     AddGadget(lb->Win->Win, &lb->UD->ScrollGad, ~0);
  1299.                     RefreshGList(&lb->UD->ScrollGad, lb->Win->Win, NULL, 1);
  1300.                     }
  1301.                 if (!lb->Enabled)
  1302.                     DisableScroller(lb->UD);
  1303.                 if (refresh)
  1304.                     ListBoxRefresh(lb);
  1305.                 }
  1306.             }
  1307.  
  1308.         if (lb->LongestIntuiLen > lb->MaxIntuiLen && !lb->LR)
  1309.             {
  1310.             lb->WidgetData->flags |= SYS_LB_HSCROLL;
  1311.             ResizeListBox(lb, lb->WidgetData->left, lb->WidgetData->top, lb->WidgetData->width, lb->WidgetData->height, (double) 1.0, (double) 1.0, TRUE);
  1312.             MakeHorizontalScroller(lb, ScrollLeftButtFn, ScrollRightButtFn);
  1313.             if (refresh)
  1314.                 ListBoxRefresh(lb);
  1315.             }
  1316.         }
  1317.     }
  1318.  
  1319. static void CheckLongestIntuiLen(ListBox *lb, ListBoxItem *last)
  1320.     {
  1321.     // last is the last item in the IntuiTextList being added.
  1322.     if (last && lb)
  1323.         {
  1324.         int Length = ItemLength(lb, last);
  1325.         if (Length > lb->LongestIntuiLen)
  1326.             {
  1327.             lb->LongestIntuiLen = Length;
  1328.             if (lb->LR)
  1329.                 UpdateHorizScroller(lb);
  1330.             }
  1331.         }
  1332.     }
  1333.  
  1334. ListBoxItem* FOXLIB ReplaceListBoxItem(REGA0 ListBox *nlb, REGA1 char *item, REGA2 ListBoxItem *OldItem, REGD0 BOOL refresh)
  1335.     {
  1336.     int Itemnum, OldLength;
  1337.     ListBoxItem *NewItem, *OldItemPointer = nlb->FirstItem, *OldItemLast, *last = NULL, *NextText;
  1338.     Diagnostic("ReplaceListBoxItem", ENTER, TRUE);
  1339.  
  1340.     // ListBox item numbers start at 1 not 0.
  1341.  
  1342.     if (!(nlb && item && OldItem))
  1343.         {
  1344.         Diagnostic("ReplaceListBoxItem", EXIT, FALSE);
  1345.         return NULL;
  1346.         }
  1347.     OldItemLast = OldItem;
  1348.     Itemnum = ItemNum(nlb, OldItem);
  1349.     if (!Itemnum)
  1350.         {
  1351.         Diagnostic("ReplaceListBoxItem", EXIT, FALSE);
  1352.         return NULL;
  1353.         }
  1354.  
  1355.     /* By copying all of the colours from the old item, the new one will be shown correctly if it
  1356.         happens to be the currently hilighted one. */
  1357.     if (!(NewItem = MakeIntuiTextList(nlb, item, OldItem->FrontPen, OldItem->BackPen,
  1358.             OldItem->TopEdge, OldItem->DrawMode, &last)))
  1359.         {
  1360.         Diagnostic("ReplaceListBoxItem", EXIT, FALSE);
  1361.         return NULL;
  1362.         }
  1363.  
  1364.     while (OldItemLast && OldItemLast->NextText && OldItemLast->NextText->TopEdge == OldItemLast->TopEdge)
  1365.         OldItemLast = OldItemLast->NextText;
  1366.  
  1367.     NextText = OldItemLast->NextText;
  1368.     OldItemLast->NextText = NULL;
  1369.     OldLength = ItemLength(nlb, OldItemLast);
  1370.     if (OldItemPointer == OldItem)
  1371.         nlb->FirstItem = NewItem;
  1372.     else
  1373.         {
  1374.         while (OldItemPointer->NextText != OldItem)
  1375.             OldItemPointer = OldItemPointer->NextText;
  1376.         OldItemPointer->NextText = NewItem;
  1377.         }
  1378.  
  1379.     if (refresh && nlb->hidden == 0)
  1380.         {
  1381.         if (!nlb->modified)
  1382.             {
  1383.             if (Itemnum >= nlb->TopShown && Itemnum < nlb->TopShown + NumLines(nlb))
  1384.                 {
  1385.                 int top;
  1386. //                BOOL unclip = FALSE;
  1387.  
  1388. /*                if (!(nlb->WidgetData->flags & LB_CLIPPED))
  1389.                     {
  1390.                     ListBoxClipOn(nlb, -1);
  1391.                     unclip = TRUE;
  1392.                     } */
  1393.                 if (nlb->NoTitles)
  1394.                     top = nlb->WidgetData->top + ((nlb->NoTitles + 1 - nlb->TopShown) * nlb->Font->ta_YSize) + (3 * nlb->TBorder) + 4;
  1395.                 else
  1396.                     top = nlb->WidgetData->top + ((1 - nlb->TopShown) * nlb->Font->ta_YSize) + nlb->TBorder + 1;
  1397.                 // Unprint the old text
  1398.                 AreaColFill(nlb->Win->Win->RPort, nlb->WidgetData->left + OldItem->LeftEdge, top + OldItem->TopEdge, nlb->MaxIntuiLen, nlb->Font->ta_YSize, (nlb->HiItem == OldItem ? OldItem->FrontPen : GetBackCol(nlb->WidgetData->Parent)));
  1399.                 // Print the new text
  1400.                 PrintTabClippedText(nlb, NewItem, top);
  1401. //                PrintIText(nlb->Win->Win->RPort, NewItem, nlb->WidgetData->left + nlb->xOffset, top);
  1402.  
  1403. /*                if (unclip)
  1404.                     ListBoxClipOff(nlb); */
  1405.                 CheckLongestIntuiLen(nlb, last);
  1406.                 }
  1407.             }
  1408.         else
  1409.             {
  1410.             last->NextText = NextText;
  1411.             ListBoxRefresh(nlb);
  1412.             }
  1413.         }
  1414.     else
  1415.         nlb->modified = TRUE;
  1416.  
  1417.     last->NextText = NextText;
  1418.     if (nlb->HiItem == OldItem)
  1419.         nlb->HiItem = NewItem;
  1420.     FreeITextList(OldItem);
  1421.     if (OldLength == nlb->LongestIntuiLen)
  1422.         SetLongestIntuiLen(nlb, 3, refresh);
  1423.     else if (ItemLength(nlb, last) == nlb->LongestIntuiLen)
  1424.         CheckMakeScrollers(nlb, refresh);
  1425.     return NewItem;
  1426.     }
  1427.  
  1428. ListBoxItem* FOXLIB AddListBoxItem(REGA0 ListBox *nlb, REGA1 char *item, REGD0 BOOL refresh)
  1429.     {
  1430.     ListBoxItem *NewItem, *last = NULL;
  1431.     unsigned short body, pot;
  1432.     int numlines;
  1433.     Diagnostic("AddListBoxItem", ENTER, TRUE);
  1434.  
  1435.     if (!(nlb && item))
  1436.         {
  1437.         Diagnostic("AddListBoxItem", EXIT, FALSE);
  1438.         return NULL;
  1439.         }
  1440.  
  1441.     numlines = NumLines(nlb);
  1442.  
  1443.     if (!(NewItem = MakeIntuiTextList(nlb, item, nlb->FrontPen, GetBackCol(nlb->WidgetData->Parent),
  1444.             nlb->NoItems * nlb->Font->ta_YSize, JAM2, &last)))
  1445.         {
  1446.         Diagnostic("AddListBoxItem", EXIT, FALSE);
  1447.         return NULL;
  1448.         }
  1449.  
  1450.     if (nlb->FirstItem == NULL)
  1451.         nlb->FirstItem = NewItem;
  1452.     else
  1453.         {
  1454.         ListBoxItem *next = nlb->FirstItem;
  1455.         while (next->NextText)
  1456.             next = next->NextText;
  1457.         next->NextText = NewItem;
  1458.         }
  1459.  
  1460.     (nlb->NoItems)++;
  1461.     if (refresh && nlb->hidden == 0)
  1462.         {
  1463.         if (!nlb->modified)
  1464.             {
  1465. /*            BOOL unclip = FALSE;
  1466.  
  1467.             if (!(nlb->WidgetData->flags & LB_CLIPPED))
  1468.                 {
  1469.                 ListBoxClipOn(nlb, -1);
  1470.                 unclip = TRUE;
  1471.                 } */
  1472.             /*    Nothing else has been changed since the last refresh so we just need
  1473.                 to draw the new item */
  1474.             if (nlb->NoItems == 1)
  1475.                 {
  1476.                 int top;
  1477.                 if (nlb->NoTitles)
  1478.                     top = nlb->WidgetData->top + (nlb->NoTitles * nlb->Font->ta_YSize) + (3 * nlb->TBorder) + 4;
  1479.                 else
  1480.                     top = nlb->WidgetData->top + nlb->TBorder + 1;
  1481.                 nlb->TopShown = 1;
  1482.                 PrintTabClippedText(nlb, NewItem, top);
  1483. //                PrintIText(nlb->Win->Win->RPort, NewItem, nlb->WidgetData->left + nlb->xOffset, top);
  1484.                 }
  1485.             else if (numlines > nlb->NoItems - nlb->TopShown)
  1486.                 {
  1487.                 int top;
  1488.                 if (nlb->NoTitles)
  1489.                     top = nlb->WidgetData->top + ((nlb->NoTitles + 1 - nlb->TopShown) * nlb->Font->ta_YSize) + (3 * nlb->TBorder) + 4;
  1490.                 else
  1491.                     top = nlb->WidgetData->top + ((1 - nlb->TopShown) * nlb->Font->ta_YSize) + nlb->TBorder + 1;
  1492.                 PrintTabClippedText(nlb, NewItem, top);
  1493. //                PrintIText(nlb->Win->Win->RPort, NewItem, nlb->WidgetData->left + nlb->xOffset, top);
  1494.                 }
  1495. //            if (unclip)
  1496. //                ListBoxClipOff(nlb);
  1497.             }
  1498.         else
  1499.             ListBoxRefresh(nlb);
  1500.  
  1501.         if (nlb->UD)
  1502.             {
  1503.             FindScrollerValues(nlb->NoItems, numlines, nlb->TopShown - 1, 1, &body, &pot);
  1504.             NewModifyProp(&nlb->UD->ScrollGad, nlb->Win->Win, NULL, AUTOKNOB | FREEVERT | PROPNEWLOOK, 0, pot, 0, body, 1);
  1505.             }
  1506.         }
  1507.     else
  1508.         nlb->modified = TRUE;
  1509.  
  1510.     CheckLongestIntuiLen(nlb, last);
  1511.     CheckMakeScrollers(nlb, refresh);
  1512.  
  1513.     Diagnostic("AddListBoxItem", EXIT, TRUE);
  1514.     return NewItem;
  1515.     }
  1516.  
  1517. ListBoxItem* FOXLIB InsertListBoxItem(REGA0 ListBox *nlb, REGA1 char *item, REGA2 ListBoxItem *after, REGD0 BOOL refresh)
  1518.     {
  1519.     ListBoxItem *NewItem, *i, *last = NULL;
  1520.     unsigned short body, pot;
  1521.     int numlines, numbefore = after ? 1 : 0;
  1522.     Diagnostic("InsertListBoxItem", ENTER, TRUE);
  1523.  
  1524.     if (!(nlb && item))
  1525.         {
  1526.         Diagnostic("InsertListBoxItem", EXIT, FALSE);
  1527.         return NULL;
  1528.         }
  1529.  
  1530.     numlines = NumLines(nlb);
  1531.  
  1532.     i = after ? nlb->FirstItem : NULL;
  1533.     while (i && after && i != after)
  1534.     {
  1535.         while (i->NextText && i->NextText->TopEdge == i->TopEdge)
  1536.             i = i->NextText;
  1537.         i = i->NextText;
  1538.         numbefore++;
  1539.     }
  1540.     if (i != after)
  1541.         {
  1542.         Diagnostic("InsertListBoxItem", EXIT, FALSE);
  1543.         return NULL;
  1544.         }
  1545.  
  1546.     if (!(NewItem = MakeIntuiTextList(nlb, item, nlb->FrontPen, GetBackCol(nlb->WidgetData->Parent),
  1547.             numbefore * nlb->Font->ta_YSize, JAM2, &last)))
  1548.         {
  1549.         Diagnostic("InsertListBoxItem", EXIT, FALSE);
  1550.         return NULL;
  1551.         }
  1552.  
  1553.     if (!after)
  1554.         {
  1555.         last->NextText = nlb->FirstItem;
  1556.         nlb->FirstItem = NewItem;
  1557.         }
  1558.     else
  1559.         {
  1560.         i = nlb->FirstItem;
  1561.         while (i && i != after)
  1562.             i = i->NextText;
  1563.         while (i->NextText && i->NextText->TopEdge == i->TopEdge)
  1564.             i = i->NextText;
  1565.         last->NextText = i->NextText;
  1566.         i->NextText = NewItem;
  1567.         }
  1568.  
  1569.     i = last->NextText;
  1570.     while (i)
  1571.     {
  1572.         i->TopEdge = i->TopEdge + nlb->Font->ta_YSize;
  1573.         if (i == nlb->HiItem) // We've inserted our new item before the hilighted one.
  1574.             nlb->HiNum++;
  1575.         i = i->NextText;
  1576.     }
  1577.  
  1578.     (nlb->NoItems)++;
  1579.     if (refresh && nlb->hidden == 0)
  1580.         {
  1581.         ListBoxRefresh(nlb);
  1582.  
  1583.         if (nlb->UD)
  1584.             {
  1585.             FindScrollerValues(nlb->NoItems, numlines, nlb->TopShown - 1, 1, &body, &pot);
  1586.             NewModifyProp(&nlb->UD->ScrollGad, nlb->Win->Win, NULL, AUTOKNOB | FREEVERT | PROPNEWLOOK, 0, pot, 0, body, 1);
  1587.             }
  1588.         }
  1589.     else
  1590.         nlb->modified = TRUE;
  1591.  
  1592.     CheckLongestIntuiLen(nlb, last);
  1593.     CheckMakeScrollers(nlb, refresh);
  1594.  
  1595.     Diagnostic("InsertListBoxItem", EXIT, TRUE);
  1596.     return NewItem;
  1597.     }
  1598.  
  1599. void FOXLIB ClearListBoxTitles(REGA0 ListBox *lb, REGD0 BOOL refresh)
  1600.     {
  1601.     if (lb)
  1602.         {
  1603.         FreeITextList(lb->FirstTitle);
  1604.         lb->FirstTitle = NULL;
  1605.         lb->NoTitles = 0;
  1606.         if (lb->UD && lb->NoItems < NumLines(lb))
  1607.             DestroyVerticalScroller(lb, refresh);
  1608.         SetLongestIntuiLen(lb, 2, refresh);
  1609.         if (refresh)
  1610.             ListBoxRefresh(lb);
  1611.         else
  1612.             lb->modified = TRUE;
  1613.         }
  1614.     }
  1615.  
  1616. void FOXLIB ClearListBoxItems(REGA0 ListBox *lb, REGD0 BOOL refresh)
  1617.     {
  1618.     if (lb)
  1619.         {
  1620.         FreeITextList(lb->FirstItem);
  1621.         lb->FirstItem = lb->HiItem = NULL;
  1622.         lb->NoItems = 0;
  1623.         lb->HiNum = 0;
  1624.         if (lb->UD && NumLines(lb) > 0)
  1625.             DestroyVerticalScroller(lb, refresh);
  1626.         SetLongestIntuiLen(lb, 1, refresh);
  1627.         if (refresh)
  1628.             ListBoxRefresh(lb);
  1629.         else
  1630.             lb->modified = TRUE;
  1631.         }
  1632.     }
  1633.  
  1634. BOOL DisableListBox(ListBox *lb)
  1635.     {
  1636.     Diagnostic("DisableListBox", ENTER, TRUE);
  1637.     if (lb)
  1638.         {
  1639.         if (lb->Enabled)
  1640.             {
  1641.             if (lb->UD)
  1642.                 DisableScroller(lb->UD);
  1643.  
  1644.             if (lb->LR)
  1645.                 DisableScroller(lb->LR);
  1646.             }
  1647.         lb->Enabled = FALSE;
  1648.         }
  1649.     return Diagnostic("DisableListBox", EXIT, lb != NULL);
  1650.     }
  1651.  
  1652. void DisableAllListBoxes(void)
  1653.     {
  1654.     ListBox *lb = Gui.FirstListBox;
  1655.     Diagnostic("DisableAllListBoxes", ENTER, TRUE);
  1656.     while (lb)
  1657.         {
  1658.         DisableListBox(lb);
  1659.         lb = lb->NextListBox;
  1660.         }
  1661.     Diagnostic("DisableAllListBoxes", EXIT, TRUE);
  1662.     }
  1663.  
  1664. void DisableWinListBoxes(GuiWindow *w)
  1665.     {
  1666.     ListBox *lb = Gui.FirstListBox;
  1667.     Diagnostic("DisableWinListBoxes", ENTER, TRUE);
  1668.     while (lb)
  1669.         {
  1670.         if (lb->Win == w)
  1671.             DisableListBox(lb);
  1672.         lb = lb->NextListBox;
  1673.         }
  1674.     Diagnostic("DisableWinListBoxes", EXIT, TRUE);
  1675.     }
  1676.  
  1677. BOOL EnableListBox(ListBox *lb)
  1678.     {
  1679.     Diagnostic("EnableListBox", ENTER, TRUE);
  1680.     if (lb)
  1681.         {
  1682.         if (lb->UD && !lb->Enabled)
  1683.             {
  1684.             // We have to pretend the button is not part of a list box or we can't enable it!
  1685.             lb->UD->ScrollUp->WidgetData->ParentControl = NULL;
  1686.             lb->UD->ScrollDown->WidgetData->ParentControl = NULL;
  1687.             EnableButton(lb->UD->ScrollUp);
  1688.             EnableButton(lb->UD->ScrollDown);
  1689.             lb->UD->ScrollUp->WidgetData->ParentControl = lb;
  1690.             lb->UD->ScrollDown->WidgetData->ParentControl = lb;
  1691.  
  1692.             if (lb->hidden == 0)
  1693.                 // Add the scroll gadget to the window's gadget list
  1694.                 AddGadget(lb->Win->Win, &lb->UD->ScrollGad, ~0);
  1695.             }
  1696.  
  1697.         if (lb->LR && !lb->Enabled)
  1698.             {
  1699.             lb->LR->ScrollUp->WidgetData->ParentControl = NULL;
  1700.             lb->LR->ScrollDown->WidgetData->ParentControl = NULL;
  1701.             EnableButton(lb->LR->ScrollUp);
  1702.             EnableButton(lb->LR->ScrollDown);
  1703.             lb->LR->ScrollUp->WidgetData->ParentControl = lb;
  1704.             lb->LR->ScrollDown->WidgetData->ParentControl = lb;
  1705.  
  1706.             if (lb->hidden == 0)
  1707.                 AddGadget(lb->Win->Win, &lb->LR->ScrollGad, ~0);
  1708.             }
  1709.  
  1710.         lb->Enabled = TRUE;
  1711.         }
  1712.     return Diagnostic("EnableListBox", EXIT, lb != NULL);
  1713.     }
  1714.  
  1715. void EnableAllListBoxes(void)
  1716.     {
  1717.     ListBox *lb = Gui.FirstListBox;
  1718.     Diagnostic("EnableAllListBoxes", ENTER, TRUE);
  1719.     while (lb)
  1720.         {
  1721.         EnableListBox(lb);
  1722.         lb = lb->NextListBox;
  1723.         }
  1724.     Diagnostic("EnableAllListBoxes", EXIT, TRUE);
  1725.     }
  1726.  
  1727. void EnableWinListBoxes(GuiWindow *w)
  1728.     {
  1729.     ListBox *lb = Gui.FirstListBox;
  1730.     Diagnostic("EnableWinListBoxes", ENTER, TRUE);
  1731.     while (lb)
  1732.         {
  1733.         if (lb->Win == w)
  1734.             EnableListBox(lb);
  1735.         lb = lb->NextListBox;
  1736.         }
  1737.     Diagnostic("EnableWinListBoxes", EXIT, TRUE);
  1738.     }
  1739.  
  1740. void FOXLIB ClearListBoxTabStops(REGA0 ListBox *nlb, REGD0 BOOL refresh)
  1741.     {
  1742.     if (nlb)
  1743.         {
  1744.         if (nlb->TabStop)
  1745.             {
  1746.             GuiFree(nlb->TabStop);
  1747.             nlb->TabStop = NULL;
  1748.             }
  1749.         if (nlb->WidgetData->os)
  1750.             if (nlb->WidgetData->os->TabStop)
  1751.                 {
  1752.                 GuiFree(nlb->WidgetData->os->TabStop);
  1753.                 nlb->WidgetData->os->TabStop = NULL;
  1754.                 }
  1755.         if (refresh)
  1756.             ListBoxRefresh(nlb);
  1757.         else
  1758.             nlb->modified = TRUE;
  1759.         }
  1760.     }
  1761.  
  1762. BOOL FOXLIB SetListBoxTabStopsArray(REGA0 ListBox *nlb, REGD0 BOOL refresh, REGD1 short num, REGA1 int *tabs)
  1763.     {
  1764.     if (nlb && num > 0)
  1765.         {
  1766.         ClearListBoxTabStops(nlb, FALSE); // Don't refresh because if refresh is TRUE it will happen later anyway.
  1767.  
  1768.         if (nlb->TabStop = (int *) GuiMalloc((num + 1) * sizeof(int), 0))
  1769.             {
  1770.             if (nlb->WidgetData->os)
  1771.                 {
  1772.                 int i;
  1773.                 if (nlb->WidgetData->os->TabStop = (int *) GuiMalloc((num + 1) * sizeof(int), 0))
  1774.                     {
  1775.                     memcpy(nlb->WidgetData->os->TabStop, tabs, num * sizeof(int));
  1776.                     nlb->WidgetData->os->TabStop[num] = 0;
  1777.                     }
  1778.                 else
  1779.                     {
  1780.                     GuiFree(nlb->TabStop);
  1781.                     nlb->TabStop = NULL;
  1782.                     return FALSE;
  1783.                     }
  1784.                 for (i = 0; i < num; i++)
  1785.                     nlb->TabStop[i] = (nlb->WidgetData->os->TabStop[i] * nlb->WidgetData->width) / nlb->WidgetData->os->width;
  1786.                 }
  1787.             else
  1788.                 memcpy(nlb->TabStop, tabs, num * sizeof(int));
  1789.             nlb->TabStop[num] = 0;
  1790.             }
  1791.         else
  1792.             return FALSE;
  1793.         if (refresh)
  1794.             ListBoxRefresh(nlb);
  1795.         else
  1796.             nlb->modified = TRUE;
  1797.         return TRUE;
  1798.         }
  1799.     return FALSE;
  1800.     }
  1801.  
  1802. BOOL SetListBoxTabStops(ListBox *nlb, BOOL refresh, short num, ...)
  1803.     {
  1804.     va_list argptr;
  1805.  
  1806.     if (nlb && num > 0)
  1807.         {
  1808.         int i;
  1809.  
  1810.         ClearListBoxTabStops(nlb, FALSE); // Don't refresh because if refresh is TRUE it will happen later anyway.
  1811.         va_start(argptr, num);
  1812.  
  1813.         if (nlb->WidgetData->os)
  1814.             {
  1815.             nlb->WidgetData->os->TabStop = (int *) GuiMalloc((num + 1) * sizeof(int), 0);
  1816.             if (!nlb->WidgetData->os->TabStop)
  1817.                 return FALSE;
  1818.             }
  1819.  
  1820.         nlb->TabStop = (int *) GuiMalloc((num + 1) * sizeof(int), 0);
  1821.         if (!nlb->TabStop)
  1822.         {
  1823.             if (nlb->WidgetData->os)
  1824.                 {
  1825.                 GuiFree(nlb->WidgetData->os->TabStop);
  1826.                 nlb->WidgetData->os->TabStop = NULL;
  1827.                 }
  1828.             return FALSE;
  1829.         }
  1830.  
  1831.         for (i = 0; i < num; i++)
  1832.             {
  1833.             if (nlb->WidgetData->os)
  1834.                 {
  1835.                 nlb->WidgetData->os->TabStop[i] = va_arg(argptr, int);
  1836.                 nlb->TabStop[i] = (nlb->WidgetData->os->TabStop[i] * nlb->WidgetData->width) / nlb->WidgetData->os->width;
  1837.                 }
  1838.             else
  1839.                 nlb->TabStop[i] = va_arg(argptr, int);
  1840.             }
  1841.         nlb->TabStop[num] = 0;
  1842.  
  1843.         va_end(argptr);
  1844.         if (refresh)
  1845.             ListBoxRefresh(nlb);
  1846.         else
  1847.             nlb->modified = TRUE;
  1848.         return TRUE;
  1849.         }
  1850.     return FALSE;
  1851.     }
  1852.  
  1853. BOOL ShowListBox(ListBox *lb)
  1854.     {
  1855.     Diagnostic("ShowListBox", ENTER, TRUE);
  1856.     if (lb)
  1857.         {
  1858.         if (lb->hidden == 1)
  1859.             {
  1860.             if (lb->UD)
  1861.                 {
  1862.                 ShowButton(lb->UD->ScrollUp);
  1863.                 ShowButton(lb->UD->ScrollDown);
  1864.                 }
  1865.             if (lb->LR)
  1866.                 {
  1867.                 ShowButton(lb->LR->ScrollUp);
  1868.                 ShowButton(lb->LR->ScrollDown);
  1869.                 }
  1870.             if ((!ISGUIWINDOW(lb->WidgetData->Parent)) && ((Frame *) lb->WidgetData->Parent)->hidden != 0)
  1871.                 lb->hidden = -1;
  1872.             else
  1873.                 {
  1874.                 if (lb->UD)
  1875.                     {
  1876.                     AddGadget(lb->Win->Win, &lb->UD->ScrollGad, ~0);
  1877.                     RefreshGList(&lb->UD->ScrollGad, lb->Win->Win, NULL, 1);
  1878.                     if (!lb->Enabled)
  1879.                         RemoveGadget(lb->Win->Win, &lb->UD->ScrollGad);
  1880.                     }
  1881.                 if (lb->LR)
  1882.                     {
  1883.                     AddGadget(lb->Win->Win, &lb->LR->ScrollGad, ~0);
  1884.                     RefreshGList(&lb->LR->ScrollGad, lb->Win->Win, NULL, 1);
  1885.                     if (!lb->Enabled)
  1886.                         RemoveGadget(lb->Win->Win, &lb->LR->ScrollGad);
  1887.                     }
  1888.                 lb->hidden = 0;
  1889.                 }
  1890.             }
  1891.         ListBoxRefresh(lb);
  1892.         return Diagnostic("ShowListBox", EXIT, TRUE);
  1893.         }
  1894.     return Diagnostic("ShowListBox", EXIT, FALSE);
  1895.     }
  1896.  
  1897. BOOL HideListBox(ListBox *lb)
  1898.     {
  1899.     Diagnostic("HideListBox", ENTER, TRUE);
  1900.     if (lb)
  1901.         {
  1902.         if (lb->UD)
  1903.             {
  1904.             HideButton(lb->UD->ScrollUp);
  1905.             HideButton(lb->UD->ScrollDown);
  1906.             }
  1907.         if (lb->LR)
  1908.             {
  1909.             HideButton(lb->LR->ScrollUp);
  1910.             HideButton(lb->LR->ScrollDown);
  1911.             }
  1912.         if (lb->hidden == 0)
  1913.             {
  1914.             if (lb->Enabled)
  1915.                 {
  1916.                 if (lb->UD)
  1917.                     RemoveGadget(lb->Win->Win, &lb->UD->ScrollGad);
  1918.                 if (lb->LR)
  1919.                     RemoveGadget(lb->Win->Win, &lb->LR->ScrollGad);
  1920.                 }
  1921.             AreaColFill(lb->Win->Win->RPort, lb->WidgetData->left, lb->WidgetData->top, lb->WidgetData->width, lb->WidgetData->height, GetBackCol(lb->WidgetData->Parent));
  1922.             }
  1923.         lb->hidden = 1;
  1924.         return Diagnostic("HideListBox", EXIT, TRUE);
  1925.         }
  1926.     return Diagnostic("HideListBox", EXIT, FALSE);
  1927.     }
  1928.  
  1929. BOOL DestroyListBox(ListBox *lb, BOOL refresh)
  1930.     {
  1931.     Diagnostic("DestroyListBox", ENTER, TRUE);
  1932.     if (lb)
  1933.         {
  1934.         Frame *Child; // Could be any type of control
  1935.         ListBox *FindIt = Gui.FirstListBox, *FIprevious = NULL;
  1936.  
  1937.         if (refresh)
  1938.             HideListBox(lb);
  1939.  
  1940.         if (lb->itemlist) // Really a tree control
  1941.             FreeItemTree(lb->itemlist, NULL, refresh);
  1942.         ClearListBoxTitles(lb, FALSE);
  1943.         ClearListBoxItems(lb, FALSE);
  1944.         ClearListBoxTabStops(lb, FALSE);
  1945.  
  1946.         if (lb->LR)
  1947.             DestroyHorizontalScroller(lb, FALSE);
  1948.  
  1949.         if (lb->UD)
  1950.             DestroyVerticalScroller(lb, FALSE);
  1951.  
  1952.         while (FindIt && FindIt != lb)
  1953.             {
  1954.             FIprevious = FindIt;
  1955.             FindIt = FindIt->NextListBox;
  1956.             }
  1957.         if (FindIt)
  1958.             {
  1959.             if (FIprevious)
  1960.                 FIprevious->NextListBox = lb->NextListBox;
  1961.             else
  1962.                 Gui.FirstListBox = lb->NextListBox;
  1963.             }
  1964.  
  1965.         if (lb->WidgetData->os)
  1966.             GuiFree(lb->WidgetData->os);
  1967.         if (lb->Font)
  1968.             {
  1969.             if (lb->Font->ta_Name)
  1970.                 GuiFree(lb->Font->ta_Name);
  1971.             GuiFree(lb->Font);
  1972.             }
  1973.         Child = lb->WidgetData->ChildWidget;
  1974.         while (Child)
  1975.             {
  1976.             void *next = Child->WidgetData->NextWidget;
  1977.             Child->WidgetData->ParentControl = NULL; // Otherwise destroy will fail.
  1978.             Destroy(Child, refresh);
  1979.             Child = next;
  1980.             }
  1981.         GuiFree(lb->WidgetData);
  1982.         GuiFree(lb);
  1983.         return Diagnostic("DestroyListBox", EXIT, TRUE);
  1984.         }
  1985.     else
  1986.         return Diagnostic("DestroyListBox", EXIT, FALSE);
  1987.     }
  1988.  
  1989. void DestroyAllListBoxes(BOOL refresh)
  1990.     {
  1991.     ListBox *lb = Gui.FirstListBox, *nlb;
  1992.     Diagnostic("DestroyAllListBoxes", ENTER, TRUE);
  1993.     while (lb)
  1994.         {
  1995.         nlb = lb->NextListBox;
  1996.         DestroyListBox(lb, refresh);
  1997.         lb = nlb;
  1998.         }
  1999.     Diagnostic("DestroyAllListBoxes", EXIT, TRUE);
  2000.     }
  2001.  
  2002. void DestroyWinListBoxes(GuiWindow *w, BOOL refresh)
  2003.     {
  2004.     BOOL message = FALSE;
  2005.     ListBox *lb = Gui.FirstListBox, *nlb;
  2006.     Diagnostic("DestroyWinListBoxes", ENTER, TRUE);
  2007.     while (lb)
  2008.         {
  2009.         nlb = lb->NextListBox;
  2010.         if (lb->Win == w)
  2011.             {
  2012.             DestroyListBox(lb, refresh);
  2013.             message = TRUE;
  2014.             }
  2015.         lb = nlb;
  2016.         }
  2017.     if (Gui.CleanupFlag && message)
  2018.         SetLastErr("Window closed before all of its list boxes were destroyed.");
  2019.     Diagnostic("DestroyWinListBoxes", EXIT, TRUE);
  2020.     }
  2021.  
  2022. void ResizeListBox(ListBox *lb, int x, int y, int width, int height, double xfactor, double yfactor, BOOL eraseold)
  2023.     {
  2024.     UWORD GadPos = (unsigned short) -1;
  2025.     int newheight = height;
  2026.  
  2027.     if (lb->WidgetData->flags & SYS_LB_HSCROLL)
  2028.         newheight = height - SCROLL_BUTTON_HEIGHT - 1;
  2029.  
  2030.     if (eraseold)
  2031.         {
  2032.         /*    If the list box is in a coloured frame then no need to blank it because the parent frame will
  2033.             blank it's entire contents. */
  2034.         if (lb->hidden == 0 && GetBackCol(lb->WidgetData->Parent) == lb->Win->Win->RPort->BgPen)
  2035.             AreaColFill(lb->Win->Win->RPort, lb->WidgetData->left, lb->WidgetData->top, lb->WidgetData->width, lb->WidgetData->height, GetBackCol(lb->WidgetData->Parent));
  2036.  
  2037.         if (lb->UD)
  2038.             {
  2039.             // returns -1 for failure.
  2040.             GadPos = RemoveGList(lb->Win->Win, &lb->UD->ScrollGad, 1L);
  2041.  
  2042.             ResizeButton(lb->UD->ScrollDown, x + width - SCROLL_BUTTON_WIDTH, y + newheight - SCROLL_BUTTON_HEIGHT, lb->UD->ScrollDown->button.Width, lb->UD->ScrollDown->button.Height, FALSE);
  2043.             ResizeButton(lb->UD->ScrollUp, x + width - SCROLL_BUTTON_WIDTH, y, lb->UD->ScrollUp->button.Width, lb->UD->ScrollUp->button.Height, FALSE);
  2044.             }
  2045.         }
  2046.  
  2047.     /*    Remember when reading the numbers below that the full width of the list box
  2048.         is width which means that it goes from left to width-1.  Similarly, it goes
  2049.         from top to height-1 */
  2050.  
  2051.     if (lb->UD)
  2052.         {
  2053.         MakeBevel(&lb->UD->LightBorder, &lb->UD->DarkBorder, lb->UD->points, x + width -
  2054.                 SCROLL_BUTTON_WIDTH, y + SCROLL_BUTTON_HEIGHT, SCROLL_BUTTON_WIDTH, newheight -
  2055.                 (2 * SCROLL_BUTTON_HEIGHT), TRUE);
  2056.         if (!lb->NoTitles)
  2057.             {
  2058.             MakeBevel(&lb->LightBorder, &lb->DarkBorder, lb->points, x, y, width - SCROLL_BUTTON_WIDTH, newheight,
  2059.                     TRUE);
  2060.             lb->DarkBorder.NextBorder = &lb->UD->LightBorder;
  2061.             }
  2062.         else
  2063.             {
  2064.             MakeBevel(&lb->LightBorder, &lb->DarkBorder, lb->points, x, y + (lb->NoTitles * lb->Font->ta_YSize)
  2065.                     + (2 * lb->TBorder) + 3, width - SCROLL_BUTTON_WIDTH, newheight - (3 + (2 * lb->TBorder) +
  2066.                     (lb->NoTitles * lb->Font->ta_YSize)), TRUE);
  2067.             MakeBevel(&lb->TitleLightBorder, &lb->TitleDarkBorder, lb->titlebevelpoints, x, y, width -
  2068.                     SCROLL_BUTTON_WIDTH, 2 + (2 * lb->TBorder) + (lb->NoTitles * lb->Font->ta_YSize), TRUE);
  2069.             lb->DarkBorder.NextBorder = &lb->TitleLightBorder;
  2070.             lb->TitleDarkBorder.NextBorder = &lb->UD->LightBorder;
  2071.             }
  2072.         if (lb->LR)
  2073.             lb->UD->DarkBorder.NextBorder = &lb->LR->LightBorder;
  2074.         /* If this definition of MaxIntuiLen (or the other below) is modified, the code in foxgui.c
  2075.             which decides how wide a pop-up list box should be must also be modified - it uses the
  2076.             reverse of the same formula to decide how wide to create the list box from the maximum
  2077.             IntuiTextLength required. */
  2078.         lb->MaxIntuiLen = width - SCROLL_BUTTON_WIDTH - 4 - (2 * lb->LBorder);
  2079.  
  2080.         lb->UD->ScrollGad.LeftEdge = x + width - SCROLL_BUTTON_WIDTH + 3;
  2081.         lb->UD->ScrollGad.TopEdge = y + SCROLL_BUTTON_HEIGHT + 3;
  2082.         lb->UD->ScrollGad.Height = newheight - (2 * SCROLL_BUTTON_HEIGHT) - 6;
  2083.         if (GadPos != -1)
  2084.             AddGList(lb->Win->Win, &lb->UD->ScrollGad, (unsigned long) GadPos, 1L, NULL);
  2085.         }
  2086.     else
  2087.         {
  2088.         if (!lb->NoTitles)
  2089.             {
  2090.             MakeBevel(&lb->LightBorder, &lb->DarkBorder, lb->points, x, y, width, newheight, TRUE);
  2091.             if (lb->LR)
  2092.                 lb->DarkBorder.NextBorder = &lb->LR->LightBorder;
  2093.             }
  2094.         else
  2095.             {
  2096.             MakeBevel(&lb->LightBorder, &lb->DarkBorder, lb->points, x, y + (lb->NoTitles *
  2097.                     lb->Font->ta_YSize) + (2 * lb->TBorder) + 3, width, newheight - (3 + (2 * lb->TBorder) +
  2098.                     (lb->NoTitles * lb->Font->ta_YSize)), TRUE);
  2099.             MakeBevel(&lb->TitleLightBorder, &lb->TitleDarkBorder, lb->titlebevelpoints, x, y, width,
  2100.                     2 + (2 * lb->TBorder) + (lb->NoTitles * lb->Font->ta_YSize), TRUE);
  2101.             lb->DarkBorder.NextBorder = &lb->TitleLightBorder;
  2102.             if (lb->LR)
  2103.                 lb->TitleDarkBorder.NextBorder = &lb->LR->LightBorder;
  2104.             }
  2105.         /* If this definition of MaxIntuiLen (or the other above) is modified, the code in foxgui.c
  2106.             which decides how wide a pop-up list box should be must also be modified - it uses the
  2107.             reverse of the same formula to decide how wide to create the list box from the maximum
  2108.             IntuiTextLength required. */
  2109.         lb->MaxIntuiLen = width - 4 - (2 * lb->LBorder);
  2110.         }
  2111.  
  2112.     lb->WidgetData->left = x;
  2113.     lb->WidgetData->top = y;
  2114.     lb->WidgetData->width = width;
  2115.     lb->WidgetData->height = height;
  2116.  
  2117.     if (lb->LR)
  2118.         ResizeHorizontalScroller(lb, x, y, width, height, xfactor, yfactor, eraseold);
  2119.     }
  2120.  
  2121. short minuspoints[] = {0, 2, 4, 2};
  2122. short pluspoints[] = {2, 0, 2, 4};
  2123.  
  2124. ListBox *CreateListBox(void *Parent, int left, int top, int width, int height, int lborder,
  2125.         int tborder, int frontpen, struct TextAttr *font, int (* __far __stdargs Eventfn) (ListBox*, short, int, void**),
  2126.         int flags, char *objecttype)
  2127. {
  2128.     ListBox *lb;
  2129.     GuiWindow *win;
  2130.     Frame *ParentFrame = NULL;
  2131.     Diagnostic("CreateListBox", ENTER, TRUE);
  2132.  
  2133.     if (!Parent)
  2134.     {
  2135.         Diagnostic("CreateListBox", EXIT, FALSE);
  2136.         return NULL;
  2137.     }
  2138.     if (!(lb = (ListBox *) GuiMalloc(sizeof(ListBox), MEMF_CLEAR)))
  2139.     {
  2140.         Diagnostic("CreateListBox", EXIT, FALSE);
  2141.         return NULL;
  2142.     }
  2143.     if (!(lb->WidgetData = (Widget *) GuiMalloc(sizeof(Widget), MEMF_CLEAR)))
  2144.     {
  2145.         GuiFree(lb);
  2146.         Diagnostic("CreateListBox", EXIT, FALSE);
  2147.         return NULL;
  2148.     }
  2149.     lb->WidgetData->Parent = Parent;
  2150.     lb->WidgetData->ObjectType = objecttype;
  2151.     lb->WidgetData->NextWidget = NULL;
  2152.     lb->WidgetData->ChildWidget = NULL;
  2153.  
  2154.     if (!ISGUIWINDOW(Parent))
  2155.     {
  2156.         ParentFrame = (Frame *) Parent;
  2157.         left += ParentFrame->button.LeftEdge;
  2158.         top += ParentFrame->button.TopEdge;
  2159.         win = (GuiWindow *) ParentFrame->button.UserData;
  2160.     }
  2161.     else
  2162.         win = (GuiWindow *) Parent;
  2163.  
  2164.     if (ParentFrame && (flags & S_AUTO_SIZE) && !(ParentFrame->WidgetData->flags & S_AUTO_SIZE))
  2165.         flags ^= S_AUTO_SIZE;
  2166.     if (flags & S_AUTO_SIZE)
  2167.     {
  2168.         if (!(lb->WidgetData->os = (OriginalSize *) GuiMalloc(sizeof(OriginalSize), 0)))
  2169.         {
  2170.             GuiFree(lb->WidgetData);
  2171.             GuiFree(lb);
  2172.             Diagnostic("CreateListBox", EXIT, FALSE);
  2173.             return NULL;
  2174.         }
  2175.         lb->WidgetData->os->left = left;
  2176.         lb->WidgetData->os->top = top;
  2177.         lb->WidgetData->os->width = width;
  2178.         lb->WidgetData->os->height = height;
  2179.         lb->WidgetData->os->TabStop = NULL;
  2180.     }
  2181.     else
  2182.         lb->WidgetData->os = NULL;
  2183.  
  2184.     lb->Eventfn = Eventfn;
  2185.     lb->WidgetData->flags = flags;
  2186.  
  2187.     MakeDownArrow(&(lb->DownArrow), frontpen);
  2188.     MakeUpArrow(&(lb->UpArrow), frontpen);
  2189.  
  2190.     if (ParentFrame && ParentFrame->hidden != 0)
  2191.         lb->hidden = -1;
  2192.     else
  2193.         lb->hidden = 0;
  2194.     lb->Enabled = TRUE;
  2195.     lb->NoItems = lb->NoTitles = lb->TopShown = 0;
  2196.     lb->Win = win;
  2197.     lb->FrontPen = frontpen;
  2198.     if (font)
  2199.         lb->Font = CopyFont(font);
  2200.     else
  2201.         lb->Font = CopyFont(&GuiFont);
  2202.  
  2203.     if (objecttype == TreeControlObjectType)
  2204.     {
  2205.         lb->plus.LeftEdge = lb->minus.LeftEdge = 3;
  2206.         lb->plus.TopEdge = lb->minus.TopEdge = (lb->Font->ta_YSize - 5) / 2;
  2207.         lb->plus.BackPen = lb->minus.BackPen = 0;
  2208.         lb->plus.FrontPen = lb->minus.FrontPen = frontpen;
  2209.         lb->plus.DrawMode = lb->minus.DrawMode = JAM1;
  2210.         lb->plus.Count = lb->minus.Count = 2;
  2211.         lb->plus.XY = pluspoints;
  2212.         lb->minus.XY = minuspoints;
  2213.         lb->plus.NextBorder = &lb->minus;
  2214.         lb->minus.NextBorder = NULL;
  2215.     }
  2216.  
  2217.     lb->LBorder = lborder;
  2218.     lb->TBorder = tborder;
  2219.     lb->HiNum = 0; // Nothing selected initially.
  2220.     lb->FirstTitle = NULL;
  2221.     lb->FirstItem = lb->HiItem = NULL;
  2222.     lb->itemlist = lb->topshown = lb->hiitem = NULL;
  2223.     lb->TabStop = NULL;
  2224.  
  2225.     /* These are set up in ResizeListBox but we have to set them up now anyway because
  2226.         MakeVerticalScroller needs them. */
  2227.     lb->WidgetData->left = left;
  2228.     lb->WidgetData->top = top;
  2229.     lb->WidgetData->width = width;
  2230.     lb->WidgetData->height = height;
  2231.  
  2232.     if (flags & SYS_LB_VSCROLL)
  2233.         MakeVerticalScroller(lb, ScrollUpButtFn, ScrollDownButtFn);
  2234.  
  2235.     ResizeListBox(lb, left, top, width, height, (double) 1.0, (double) 1.0, FALSE);
  2236.  
  2237.     if (lb->hidden == 0 && lb->UD)
  2238.     {
  2239.         AddGadget(lb->Win->Win, &lb->UD->ScrollGad, ~0);
  2240.         RefreshGList(&lb->UD->ScrollGad, lb->Win->Win, NULL, 1);
  2241.     }
  2242.  
  2243.     lb->NextListBox = Gui.FirstListBox;
  2244.     Gui.FirstListBox = lb;
  2245.  
  2246.     if (lb->hidden == 0)
  2247.         DrawBorder(win->Win->RPort, &lb->LightBorder, 0, 0);
  2248.     Diagnostic("CreateListBox", EXIT, TRUE);
  2249.     return lb;
  2250. }
  2251.  
  2252. #ifdef OLDWAY
  2253. ListBox *CreateListBox(void *Parent, int left, int top, int width, int height, int lborder,
  2254.         int tborder, int frontpen, struct TextAttr *font, int (* __far __stdargs Eventfn) (ListBox*, short, int, void**),
  2255.         int flags)
  2256.     {
  2257.     ListBox *lb;
  2258.     GuiWindow *win;
  2259.     Frame *ParentFrame = NULL;
  2260.     Diagnostic("CreateListBox", ENTER, TRUE);
  2261.  
  2262.     if (!Parent)
  2263.         {
  2264.         Diagnostic("CreateListBox", EXIT, FALSE);
  2265.         return NULL;
  2266.         }
  2267.     if (!(lb = (ListBox *) GuiMalloc(sizeof(ListBox), MEMF_CLEAR)))
  2268.         {
  2269.         Diagnostic("CreateListBox", EXIT, FALSE);
  2270.         return NULL;
  2271.         }
  2272.     lb->WidgetData->Parent = Parent;
  2273.     lb->WidgetData->ObjectType = ListBoxObject;
  2274.  
  2275.     if (!ISGUIWINDOW(Parent))
  2276.         {
  2277.         ParentFrame = (Frame *) Parent;
  2278.         left += ParentFrame->button.LeftEdge;
  2279.         top += ParentFrame->button.TopEdge;
  2280.         win = (GuiWindow *) ParentFrame->button.UserData;
  2281.         }
  2282.     else
  2283.         win = (GuiWindow *) Parent;
  2284.  
  2285.     if (ParentFrame && (flags & S_AUTO_SIZE) && !(ParentFrame->WidgetData->flags & S_AUTO_SIZE))
  2286.         flags ^= S_AUTO_SIZE;
  2287.     if (flags & S_AUTO_SIZE)
  2288.         {
  2289.         if (!(lb->WidgetData->os = (OriginalSize *) GuiMalloc(sizeof(OriginalSize), 0)))
  2290.             {
  2291.             GuiFree(lb);
  2292.             Diagnostic("CreateListBox", EXIT, FALSE);
  2293.             return NULL;
  2294.             }
  2295.         lb->WidgetData->os->left = left;
  2296.         lb->WidgetData->os->top = top;
  2297.         lb->WidgetData->os->width = width;
  2298.         lb->WidgetData->os->height = height;
  2299.         lb->WidgetData->os->TabStop = NULL;
  2300.         }
  2301.     else
  2302.         lb->WidgetData->os = NULL;
  2303.  
  2304.     lb->Eventfn = Eventfn;
  2305.     lb->WidgetData->flags = flags;
  2306.  
  2307.     MakeDownArrow(&(lb->DownArrow), frontpen);
  2308.     MakeUpArrow(&(lb->UpArrow), frontpen);
  2309.  
  2310.     if (ParentFrame && ParentFrame->hidden != 0)
  2311.         lb->hidden = -1;
  2312.     else
  2313.         lb->hidden = 0;
  2314.     lb->Enabled = TRUE;
  2315.     lb->NoItems = lb->NoTitles = lb->TopShown = 0;
  2316.     lb->Win = win;
  2317.     lb->FrontPen = frontpen;
  2318.     if (font)
  2319.         lb->Font = font;
  2320.     else if (win->ParentScreen->Font)
  2321.         lb->Font = win->ParentScreen->Font;
  2322.     else
  2323.         lb->Font = &GuiFont;
  2324.     lb->LBorder = lborder;
  2325.     lb->TBorder = tborder;
  2326.     lb->HiNum = 0; // Nothing selected initially.
  2327.     lb->FirstTitle = NULL;
  2328.     lb->FirstItem = lb->HiItem = NULL;
  2329.     lb->TabStop = NULL;
  2330.  
  2331.     /* These are set up in ResizeListBox but we have to set them up now anyway because
  2332.         MakeVerticalScroller needs them. */
  2333.     lb->WidgetData->left = left;
  2334.     lb->WidgetData->top = top;
  2335.     lb->WidgetData->width = width;
  2336.     lb->WidgetData->height = height;
  2337.  
  2338.     if (flags & SYS_LB_VSCROLL)
  2339.         MakeVerticalScroller(lb, ScrollUpButtFn, ScrollDownButtFn);
  2340.  
  2341.     ResizeListBox(lb, left, top, width, height, (double) 1.0, (double) 1.0, FALSE);
  2342.  
  2343.     if (lb->hidden == 0 && lb->UD)
  2344.         {
  2345.         AddGadget(lb->Win->Win, &lb->UD->ScrollGad, ~0);
  2346.         RefreshGList(&lb->UD->ScrollGad, lb->Win->Win, NULL, 1);
  2347.         }
  2348.  
  2349.     lb->NextListBox = Gui.FirstListBox;
  2350.     Gui.FirstListBox = lb;
  2351.  
  2352.     if (lb->hidden == 0)
  2353.         DrawBorder(win->Win->RPort, &lb->LightBorder, 0, 0);
  2354.     Diagnostic("CreateListBox", EXIT, TRUE);
  2355.     return lb;
  2356.     }
  2357. #endif
  2358.  
  2359. ListBox* FOXLIB MakeListBox(REGA0 void *Parent, REGD0 int left, REGD1 int top, REGD2 int width, REGD3 int height, REGD4 int lborder,
  2360.         REGD5 int tborder, REGD6 int flags, REGA1 int (* __far __stdargs Eventfn) (ListBox*, short, int, void**), REGA2 void *extension)
  2361.     {
  2362.     ListBox *lb;
  2363.  
  2364.     Diagnostic("MakeListBox", ENTER, TRUE);
  2365.  
  2366.     lb = CreateListBox(Parent, left, top, width, height, lborder, tborder, Gui.TextCol, &GuiFont, Eventfn,
  2367.             flags, ListBoxObject);
  2368.  
  2369.     Diagnostic("MakeListBox", EXIT, (lb != NULL));
  2370.     return lb;
  2371.     }
  2372.  
  2373. void FOXLIB SetListBoxDragPointer(REGA0 ListBox *lb, REGA1 unsigned short *DragPointer, REGD0 int width, REGD1 int height,
  2374.         REGD2 int xoffset, REGD3 int yoffset)
  2375. {
  2376.     if (lb)
  2377.     {
  2378.         lb->DragPointer = DragPointer;
  2379.         lb->PointerWidth = width;
  2380.         lb->PointerHeight = height;
  2381.         lb->PointerXOffset = xoffset;
  2382.         lb->PointerYOffset = yoffset;
  2383.     }
  2384. }
  2385.